From 8a2a1d6d70b4847d5eaff94c950de15902bab7bc Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 30 Nov 2021 19:02:27 +0100 Subject: [PATCH 1/2] :recycle: Ensure a correct usage of concat/into operations. --- backend/src/app/util/emails.clj | 3 +- common/dev/user.clj | 2 +- common/src/app/common/data.cljc | 59 ++++-- common/src/app/common/geom/align.cljc | 7 +- common/src/app/common/geom/shapes/path.cljc | 55 +++--- common/src/app/common/pages/changes.cljc | 2 +- .../src/app/common/pages/changes_builder.cljc | 2 +- common/src/app/common/pages/helpers.cljc | 38 ++-- common/src/app/common/pages/indices.cljc | 17 +- common/src/app/common/path/bool.cljc | 20 +- .../src/app/common/path/shapes_to_path.cljc | 33 ++-- common/src/app/common/path/subpaths.cljc | 2 +- common/test/app/common/data_test.clj | 58 ++++++ exporter/src/app/renderer/svg.cljs | 6 +- frontend/src/app/main/data/workspace.cljs | 64 +++---- .../src/app/main/data/workspace/changes.cljs | 2 +- .../src/app/main/data/workspace/groups.cljs | 80 ++++---- .../app/main/data/workspace/libraries.cljs | 16 +- .../data/workspace/libraries_helpers.cljs | 178 +++++++++--------- .../app/main/data/workspace/path/state.cljs | 10 +- .../app/main/data/workspace/svg_upload.cljs | 6 +- .../app/main/data/workspace/transforms.cljs | 36 ++-- frontend/src/app/main/snap.cljs | 8 +- frontend/src/app/main/ui/measurements.cljs | 2 +- .../src/app/main/ui/settings/options.cljs | 5 +- frontend/src/app/main/ui/shapes/filters.cljs | 3 +- .../app/main/ui/viewer/handoff/exports.cljs | 2 +- .../src/app/main/ui/viewer/interactions.cljs | 2 +- frontend/src/app/main/ui/viewer/shapes.cljs | 3 +- .../main/ui/workspace/shapes/path/editor.cljs | 5 +- .../sidebar/options/menus/exports.cljs | 2 +- .../workspace/sidebar/options/menus/text.cljs | 30 +-- .../sidebar/options/shapes/multiple.cljs | 2 +- .../main/ui/workspace/sidebar/sitemap.cljs | 2 +- .../app/main/ui/workspace/viewport/hooks.cljs | 6 +- .../ui/workspace/viewport/snap_distances.cljs | 10 +- .../ui/workspace/viewport/snap_points.cljs | 2 +- frontend/src/app/util/path/parser.cljs | 16 +- frontend/src/app/util/path/tools.cljs | 4 +- frontend/src/app/util/svg.cljs | 5 +- frontend/src/app/worker/export.cljs | 2 +- frontend/src/app/worker/selection.cljs | 2 +- frontend/src/app/worker/snaps.cljs | 10 +- 43 files changed, 446 insertions(+), 373 deletions(-) create mode 100644 common/test/app/common/data_test.clj diff --git a/backend/src/app/util/emails.clj b/backend/src/app/util/emails.clj index 948ebe437e..0ff6b3eb66 100644 --- a/backend/src/app/util/emails.clj +++ b/backend/src/app/util/emails.clj @@ -6,7 +6,6 @@ (ns app.util.emails (:require - [app.common.data :as d] [app.common.exceptions :as ex] [app.common.spec :as us] [app.util.template :as tmpl] @@ -199,7 +198,7 @@ (ex/raise :type :internal :code :missing-email-templates)) {:subject subj - :body (d/concat + :body (into [{:type "text/plain" :content text}] (when html diff --git a/common/dev/user.clj b/common/dev/user.clj index 10336b4f31..414a751f3a 100644 --- a/common/dev/user.clj +++ b/common/dev/user.clj @@ -37,7 +37,7 @@ ;; --- Development Stuff (defn- run-tests - ([] (run-tests #"^app.common.tests.*")) + ([] (run-tests #"^app.common.*-test$")) ([o] (repl/refresh) (cond diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index 77dcae0101..a39c6c38af 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -6,7 +6,7 @@ (ns app.common.data "Data manipulation and query helper functions." - (:refer-clojure :exclude [concat read-string hash-map merge name]) + (:refer-clojure :exclude [read-string hash-map merge name]) #?(:cljs (:require-macros [app.common.data])) (:require @@ -60,19 +60,37 @@ m) (dissoc m k))) -(defn concat - [& colls] - (loop [result (transient (first colls)) - colls (next colls)] +(defn- transient-concat + [c1 colls] + (loop [result (transient c1) + colls colls] (if colls (recur (reduce conj! result (first colls)) (next colls)) (persistent! result)))) +(defn concat-set + ([] #{}) + ([c1] + (if (set? c1) c1 (into #{} c1))) + ([c1 & more] + (if (set? c1) + (transient-concat c1 more) + (transient-concat #{} (cons c1 more))))) + +(defn concat-vec + ([] []) + ([c1] + (if (vector? c1) c1 (into [] c1))) + ([c1 & more] + (if (vector? c1) + (transient-concat c1 more) + (transient-concat [] (cons c1 more))))) + (defn preconj [coll elem] (assert (vector? coll)) - (concat [elem] coll)) + (into [elem] coll)) (defn enumerate ([items] (enumerate items 0)) @@ -144,10 +162,15 @@ (reduce #(dissoc! %1 %2) (transient data) keys)))) (defn remove-at-index + "Takes a vector and returns a vector with an element in the + specified index removed." [v index] - (vec (core/concat - (subvec v 0 index) - (subvec v (inc index))))) + ;; The subvec function returns a SubVector type that is an vector + ;; but does not have transient impl, because of this, we need to + ;; pass an explicit vector as first argument. + (concat-vec [] + (subvec v 0 index) + (subvec v (inc index)))) (defn zip [col1 col2] (map vector col1 col2)) @@ -433,18 +456,18 @@ (str maybe-keyword))))) (defn with-next - "Given a collectin will return a new collection where each element - is paried with the next item in the collection - (with-next (range 5)) => [[0 1] [1 2] [2 3] [3 4] [4 nil]" + "Given a collection will return a new collection where each element + is paired with the next item in the collection + (with-next (range 5)) => [[0 1] [1 2] [2 3] [3 4] [4 nil]]" [coll] (map vector coll - (concat [] (rest coll) [nil]))) + (concat (rest coll) [nil]))) (defn with-prev - "Given a collectin will return a new collection where each element - is paried with the previous item in the collection - (with-prev (range 5)) => [[0 nil] [1 0] [2 1] [3 2] [4 3]" + "Given a collection will return a new collection where each element + is paired with the previous item in the collection + (with-prev (range 5)) => [[0 nil] [1 0] [2 1] [3 2] [4 3]]" [coll] (map vector coll @@ -453,12 +476,12 @@ (defn with-prev-next "Given a collection will return a new collection where every item is paired with the previous and the next item of a collection - (with-prev-next (range 5)) => [[0 nil 1] [1 0 2] [2 1 3] [3 2 4] [4 3 nil]" + (with-prev-next (range 5)) => [[0 nil 1] [1 0 2] [2 1 3] [3 2 4] [4 3 nil]]" [coll] (map vector coll (concat [nil] coll) - (concat [] (rest coll) [nil]))) + (concat (rest coll) [nil]))) (defn prefix-keyword "Given a keyword and a prefix will return a new keyword with the prefix attached diff --git a/common/src/app/common/geom/align.cljc b/common/src/app/common/geom/align.cljc index 45d8b43210..ad0a35adc3 100644 --- a/common/src/app/common/geom/align.cljc +++ b/common/src/app/common/geom/align.cljc @@ -6,7 +6,6 @@ (ns app.common.geom.align (:require - [app.common.data :as d] [app.common.geom.shapes :as gsh] [clojure.spec.alpha :as s])) @@ -16,11 +15,15 @@ (declare calc-align-pos) +;; TODO: revisit on how to reuse code and dont have this function +;; duplicated because the implementation right now differs from the +;; original function. + ;; Duplicated from pages/helpers to remove cyclic dependencies (defn- get-children [id objects] (let [shapes (vec (get-in objects [id :shapes]))] (if shapes - (d/concat shapes (mapcat #(get-children % objects) shapes)) + (into shapes (mapcat #(get-children % objects)) shapes) []))) (defn- recursive-move diff --git a/common/src/app/common/geom/shapes/path.cljc b/common/src/app/common/geom/shapes/path.cljc index d8bd67cfc8..80d601bb12 100644 --- a/common/src/app/common/geom/shapes/path.cljc +++ b/common/src/app/common/geom/shapes/path.cljc @@ -100,7 +100,7 @@ (defn curve-tangent "Retrieve the tangent vector to the curve in the point `t`" [[start end h1 h2] t] - + (let [coords [[(:x start) (:x h1) (:x h2) (:x end)] [(:y start) (:y h1) (:y h2) (:y end)]] @@ -316,15 +316,13 @@ :line-to [prev-point (command->point command)] ;; We return the bezier extremities - :curve-to (d/concat - [prev-point - (command->point command)] - (let [curve [prev-point - (command->point command) - (command->point command :c1) - (command->point command :c2)]] - (->> (curve-extremities curve) - (mapv #(curve-values curve %))))) + :curve-to (into [prev-point (command->point command)] + (let [curve [prev-point + (command->point command) + (command->point command :c1) + (command->point command :c2)]] + (->> (curve-extremities curve) + (map #(curve-values curve %))))) []) selrect (gpr/points->selrect points)] (-> selrect @@ -342,20 +340,19 @@ (command->point command)] ;; We return the bezier extremities - :curve-to (d/concat - [(command->point prev) - (command->point command)] - (let [curve [(command->point prev) - (command->point command) - (command->point command :c1) - (command->point command :c2)]] - (->> (curve-extremities curve) - (mapv #(curve-values curve %))))) + :curve-to (into [(command->point prev) + (command->point command)] + (let [curve [(command->point prev) + (command->point command) + (command->point command :c1) + (command->point command :c2)]] + (->> (curve-extremities curve) + (map #(curve-values curve %))))) [])) extremities (mapcat calc-extremities content - (d/concat [nil] content)) + (concat [nil] content)) selrect (gpr/points->selrect extremities)] @@ -410,14 +407,16 @@ (let [initial (first segments) lines (rest segments)] - (d/concat [{:command :move-to - :params (select-keys initial [:x :y])}] - (->> lines - (mapv #(hash-map :command :line-to - :params (select-keys % [:x :y])))) + (d/concat-vec + [{:command :move-to + :params (select-keys initial [:x :y])}] - (when closed? - [{:command :close-path}]))))) + (->> lines + (map #(hash-map :command :line-to + :params (select-keys % [:x :y])))) + + (when closed? + [{:command :close-path}]))))) (defonce num-segments 10) @@ -770,7 +769,7 @@ ts-3 (check-range c1-half c1-to c2-from c2-half) ts-4 (check-range c1-half c1-to c2-half c2-to)] - (d/concat [] ts-1 ts-2 ts-3 ts-4))))))) + (d/concat-vec ts-1 ts-2 ts-3 ts-4))))))) (remove-close-ts [{cp1 :p1 cp2 :p2}] (fn [{:keys [p1 p2]}] diff --git a/common/src/app/common/pages/changes.cljc b/common/src/app/common/pages/changes.cljc index a2211b238c..dd469f2542 100644 --- a/common/src/app/common/pages/changes.cljc +++ b/common/src/app/common/pages/changes.cljc @@ -214,7 +214,7 @@ not-mask-shapes (without-obj shapes mask-id) new-index (if (nil? index) nil (max (dec index) 0)) new-shapes (insert-items other-ids new-index not-mask-shapes)] - (d/concat [mask-id] new-shapes)))) + (into [mask-id] new-shapes)))) (add-to-parent [parent index shapes] (let [parent (-> parent diff --git a/common/src/app/common/pages/changes_builder.cljc b/common/src/app/common/pages/changes_builder.cljc index 45fcebd23a..d999822bd7 100644 --- a/common/src/app/common/pages/changes_builder.cljc +++ b/common/src/app/common/pages/changes_builder.cljc @@ -97,7 +97,7 @@ (let [old-obj (get objects id) new-obj (update-fn old-obj) - attrs (or attrs (d/concat #{} (keys old-obj) (keys new-obj))) + attrs (or attrs (d/concat-set (keys old-obj) (keys new-obj))) {rops :rops uops :uops} (reduce #(generate-operation %1 %2 old-obj new-obj ignore-geometry?) diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index 9099088203..6418674750 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -103,7 +103,6 @@ "Retrieve all children ids recursively for a given object. The children's order will be breadth first." [id objects] - (loop [result (transient []) pending (transient []) next id] @@ -214,10 +213,10 @@ [objects index ids] (let [[before after] (split-at index objects) p? (set ids)] - (d/concat [] - (remove p? before) - ids - (remove p? after)))) + (d/concat-vec [] + (remove p? before) + ids + (remove p? after)))) (defn append-at-the-end [prev-ids ids] @@ -233,24 +232,25 @@ ([objects {:keys [include-frames? include-frame-children?] :or {include-frames? false include-frame-children? true}}] - (let [lookup #(get objects %) - root (lookup uuid/zero) + + (let [lookup #(get objects %) + root (lookup uuid/zero) root-children (:shapes root) lookup-shapes (fn [result id] (if (nil? id) result - (let [obj (lookup id) - typ (:type obj) + (let [obj (lookup id) + typ (:type obj) children (:shapes obj)] (cond-> result (or (not= :frame typ) include-frames?) - (d/concat [obj]) + (conj obj) (and (= :frame typ) include-frame-children?) - (d/concat (map lookup children))))))] + (into (map lookup) children)))))] (reduce lookup-shapes [] root-children)))) @@ -299,15 +299,13 @@ (some? (:shapes object)) (assoc :shapes (mapv :id new-direct-children))) - new-object (update-new-object new-object object) - - new-objects (d/concat [new-object] new-children) - - updated-object (update-original-object object new-object) + new-object (update-new-object new-object object) + new-objects (into [new-object] new-children) + updated-object (update-original-object object new-object) updated-objects (if (identical? object updated-object) updated-children - (d/concat [updated-object] updated-children))] + (into [updated-object] updated-children))] [new-object new-objects updated-objects]) @@ -320,9 +318,9 @@ (recur (next child-ids) - (d/concat new-direct-children [new-child]) - (d/concat new-children new-child-objects) - (d/concat updated-children updated-child-objects)))))))) + (into new-direct-children [new-child]) + (into new-children new-child-objects) + (into updated-children updated-child-objects)))))))) (defn indexed-shapes "Retrieves a list with the indexes for each element in the layer tree. diff --git a/common/src/app/common/pages/indices.cljc b/common/src/app/common/pages/indices.cljc index 5a5f405959..8145d2f0ae 100644 --- a/common/src/app/common/pages/indices.cljc +++ b/common/src/app/common/pages/indices.cljc @@ -12,28 +12,25 @@ [clojure.set :as set])) (defn calculate-frame-z-index [z-index frame-id objects] - (let [is-frame? (fn [id] (= :frame (get-in objects [id :type]))) + (let [is-frame? (fn [id] (= :frame (get-in objects [id :type]))) frame-shapes (->> objects (vals) (filterv #(= (:frame-id %) frame-id))) - children (or (get-in objects [frame-id :shapes]) [])] + children (or (get-in objects [frame-id :shapes]) [])] (if (empty? children) z-index - (loop [current (peek children) pending (pop children) current-idx (count frame-shapes) z-index z-index] - (let [children (get-in objects [current :shapes]) + (let [children (get-in objects [current :shapes]) is-frame? (is-frame? current) - pending (if (not is-frame?) - (d/concat pending children) - pending)] + pending (if (not is-frame?) + (d/concat-vec pending children) + pending)] (if (empty? pending) - (-> z-index - (assoc current current-idx)) - + (assoc z-index current current-idx) (recur (peek pending) (pop pending) (dec current-idx) diff --git a/common/src/app/common/path/bool.cljc b/common/src/app/common/path/bool.cljc index 8269c1e287..0c13503ae4 100644 --- a/common/src/app/common/path/bool.cljc +++ b/common/src/app/common/path/bool.cljc @@ -213,26 +213,25 @@ ;; Pick all segments in content-a that are not inside content-b ;; Pick all segments in content-b that are not inside content-a (let [content - (d/concat - [] + (concat (->> content-a-split (filter #(not (contains-segment? % content-b)))) (->> content-b-split (filter #(not (contains-segment? % content-a))))) ;; Overlapping segments should be added when they are part of the border border-content (->> content-b-split - (filterv #(and (contains-segment? % content-a) - (overlap-segment? % content-a-split) - (not (inside-segment? % content)))))] + (filter #(and (contains-segment? % content-a) + (overlap-segment? % content-a-split) + (not (inside-segment? % content)))))] - (d/concat content border-content))) + ;; Ensure that the output is always a vector + (d/concat-vec content border-content))) (defn create-difference [content-a content-a-split content-b content-b-split] ;; Pick all segments in content-a that are not inside content-b ;; Pick all segments in content b that are inside content-a ;; removing overlapping - (d/concat - [] + (d/concat-vec (->> content-a-split (filter #(not (contains-segment? % content-b)))) ;; Reverse second content so we can have holes inside other shapes @@ -243,15 +242,14 @@ (defn create-intersection [content-a content-a-split content-b content-b-split] ;; Pick all segments in content-a that are inside content-b ;; Pick all segments in content-b that are inside content-a - (d/concat - [] + (d/concat-vec (->> content-a-split (filter #(contains-segment? % content-b))) (->> content-b-split (filter #(contains-segment? % content-a))))) (defn create-exclusion [content-a content-b] ;; Pick all segments - (d/concat [] content-a content-b)) + (d/concat-vec content-a content-b)) (defn fix-move-to diff --git a/common/src/app/common/path/shapes_to_path.cljc b/common/src/app/common/path/shapes_to_path.cljc index 3a60ebbd54..4cb03272b3 100644 --- a/common/src/app/common/path/shapes_to_path.cljc +++ b/common/src/app/common/path/shapes_to_path.cljc @@ -31,23 +31,22 @@ :blur]) (def style-properties - (d/concat - style-group-properties - [:fill-color - :fill-opacity - :fill-color-gradient - :fill-color-ref-file - :fill-color-ref-id - :fill-image - :stroke-color - :stroke-color-ref-file - :stroke-color-ref-id - :stroke-opacity - :stroke-style - :stroke-width - :stroke-alignment - :stroke-cap-start - :stroke-cap-end])) + (into style-group-properties + [:fill-color + :fill-opacity + :fill-color-gradient + :fill-color-ref-file + :fill-color-ref-id + :fill-image + :stroke-color + :stroke-color-ref-file + :stroke-color-ref-id + :stroke-opacity + :stroke-style + :stroke-width + :stroke-alignment + :stroke-cap-start + :stroke-cap-end])) (defn make-corner-arc "Creates a curvle corner for border radius" diff --git a/common/src/app/common/path/subpaths.cljc b/common/src/app/common/path/subpaths.cljc index 202e273b1d..aed3171950 100644 --- a/common/src/app/common/path/subpaths.cljc +++ b/common/src/app/common/path/subpaths.cljc @@ -90,7 +90,7 @@ [subpath other] (assert (pt= (:to subpath) (:from other))) (-> subpath - (update :data d/concat (rest (:data other))) + (update :data d/concat-vec (rest (:data other))) (assoc :to (:to other)))) (defn- merge-paths diff --git a/common/test/app/common/data_test.clj b/common/test/app/common/data_test.clj new file mode 100644 index 0000000000..8a85bb97b1 --- /dev/null +++ b/common/test/app/common/data_test.clj @@ -0,0 +1,58 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) UXBOX Labs SL + +(ns app.common.data-test + (:require + [app.common.data :as d] + [clojure.test :as t])) + +(t/deftest concat-vec + (t/is (= [1 2 3] + (d/concat-vec [1] #{2} [3]))) + + (t/is (= [1 2] + (d/concat-vec '(1) [2]))) + + (t/is (= [1] + (d/concat-vec [1]))) + + (t/is (= [] (d/concat-vec)))) + +(t/deftest concat-set + (t/is (= #{} (d/concat-set))) + (t/is (= #{1 2} + (d/concat-set [1] [2])))) + +(t/deftest remove-at-index + (t/is (= [1 2 3 4] + (d/remove-at-index [1 2 3 4 5] 4))) + + + (t/is (= [1 2 3 4] + (d/remove-at-index [5 1 2 3 4] 0))) + + (t/is (= [1 2 3 4] + (d/remove-at-index [1 5 2 3 4] 1))) + ) + +(t/deftest with-next + (t/is (= [[0 1] [1 2] [2 3] [3 4] [4 nil]] + (d/with-next (range 5))))) + +(t/deftest with-prev + (t/is (= [[0 nil] [1 0] [2 1] [3 2] [4 3]] + (d/with-prev (range 5))))) + +(t/deftest with-prev-next + (t/is (= [[0 nil 1] [1 0 2] [2 1 3] [3 2 4] [4 3 nil]] + (d/with-prev-next (range 5))))) + +(t/deftest join + (t/is (= [[1 :a] [1 :b] [2 :a] [2 :b] [3 :a] [3 :b]] + (d/join [1 2 3] [:a :b]))) + (t/is (= [1 10 100 2 20 200 3 30 300] + (d/join [1 2 3] [1 10 100] *)))) + diff --git a/exporter/src/app/renderer/svg.cljs b/exporter/src/app/renderer/svg.cljs index ca789f2e0e..274cdfc6bc 100644 --- a/exporter/src/app/renderer/svg.cljs +++ b/exporter/src/app/renderer/svg.cljs @@ -201,7 +201,7 @@ (recur (->> (get svgdata "elements") (filter #(= (get % "name") "g")) (map (partial set-path-color id color mapping)) - (update result "elements" d/concat)) + (update result "elements" into)) (rest layers)) ;; Now we have the result containing the svgdata of a @@ -232,8 +232,8 @@ elements (cond->> elements (not (empty? gradient-defs)) - (d/concat [{"type" "element" "name" "defs" "attributes" {} - "elements" gradient-defs}]))] + (into [{"type" "element" "name" "defs" "attributes" {} + "elements" gradient-defs}]))] (-> result (assoc "name" "g") diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index e5e36f6ab4..8e905b220c 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -546,7 +546,7 @@ (disj flags flag) (conj flags flag))) stored - (into #{} flags))))))) + (d/concat-set flags))))))) ;; --- Set element options mode @@ -784,8 +784,7 @@ groups-to-delete) u-del-change - (d/concat - [] + (concat ;; Create the groups (map (fn [group-id] (let [group (get objects group-id)] @@ -936,25 +935,25 @@ :page-id page-id :shapes (vec parents)}] - rchanges (d/concat [] - r-mov-change - r-del-change - r-mask-change - r-detach-change - r-deroot-change - r-reroot-change - r-unconstraint-change - r-reg-change) + rchanges (d/concat-vec + r-mov-change + r-del-change + r-mask-change + r-detach-change + r-deroot-change + r-reroot-change + r-unconstraint-change + r-reg-change) - uchanges (d/concat [] - u-del-change - u-reroot-change - u-deroot-change - u-detach-change - u-mask-change - u-mov-change - u-unconstraint-change - u-reg-change)] + uchanges (d/concat-vec + u-del-change + u-reroot-change + u-deroot-change + u-detach-change + u-mask-change + u-mov-change + u-unconstraint-change + u-reg-change)] [rchanges uchanges])) (defn relocate-shapes @@ -970,18 +969,15 @@ objects (wsh/lookup-page-objects state page-id) ;; Ignore any shape whose parent is also intented to be moved - ids (cp/clean-loops objects ids) + ids (cp/clean-loops objects ids) ;; If we try to move a parent into a child we remove it - ids (filter #(not (cp/is-parent? objects parent-id %)) ids) - - parents (reduce (fn [result id] - (conj result (cp/get-parent id objects))) - #{parent-id} ids) + ids (filter #(not (cp/is-parent? objects parent-id %)) ids) + parents (into #{parent-id} (map #(cp/get-parent % objects)) ids) groups-to-delete - (loop [current-id (first parents) - to-check (rest parents) + (loop [current-id (first parents) + to-check (rest parents) removed-id? (set ids) result #{}] @@ -995,7 +991,7 @@ (empty? (remove removed-id? (:shapes group)))) ;; Adds group to the remove and check its parent - (let [to-check (d/concat [] to-check [(cp/get-parent current-id objects)]) ] + (let [to-check (concat to-check [(cp/get-parent current-id objects)])] (recur (first to-check) (rest to-check) (conj removed-id? current-id) @@ -1022,6 +1018,10 @@ #{} ids) + ;; TODO: Probably implementing this using loop/recur will + ;; be more efficient than using reduce and continuos data + ;; desturcturing. + ;; Sets the correct components metadata for the moved shapes ;; `shapes-to-detach` Detach from a component instance a shape that was inside a component and is moved outside ;; `shapes-to-deroot` Removes the root flag from a component instance moved inside another component @@ -1111,7 +1111,7 @@ (defn relocate-page [id index] - (ptk/reify ::relocate-pages + (ptk/reify ::relocate-page ptk/WatchEvent (watch [it state _] (let [cidx (-> (get-in state [:workspace-data :pages]) @@ -1209,7 +1209,7 @@ (boolean? hidden) (assoc :hidden hidden))) objects (wsh/lookup-page-objects state) - ids (d/concat [id] (cp/get-children id objects))] + ids (into [id] (cp/get-children id objects))] (rx/of (dch/update-shapes ids update-fn)))))) diff --git a/frontend/src/app/main/data/workspace/changes.cljs b/frontend/src/app/main/data/workspace/changes.cljs index 99c050db68..7b481bff39 100644 --- a/frontend/src/app/main/data/workspace/changes.cljs +++ b/frontend/src/app/main/data/workspace/changes.cljs @@ -50,7 +50,7 @@ (let [old-obj (get objects id) new-obj (update-fn old-obj) - attrs (or attrs (d/concat #{} (keys old-obj) (keys new-obj))) + attrs (or attrs (d/concat-set (keys old-obj) (keys new-obj))) {rops :rops uops :uops} (reduce #(generate-operation %1 %2 old-obj new-obj ignore-geometry?) diff --git a/frontend/src/app/main/data/workspace/groups.cljs b/frontend/src/app/main/data/workspace/groups.cljs index 11605a13bf..c3a8acd0ad 100644 --- a/frontend/src/app/main/data/workspace/groups.cljs +++ b/frontend/src/app/main/data/workspace/groups.cljs @@ -51,7 +51,7 @@ (empty? (remove removed-id? (:shapes group)))) ;; Adds group to the remove and check its parent - (let [to-check (d/concat [] to-check [(cp/get-parent current-id objects)]) ] + (let [to-check (concat to-check [(cp/get-parent current-id objects)]) ] (recur (first to-check) (rest to-check) (conj removed-id? current-id) @@ -131,6 +131,7 @@ uchanges (->> ids-to-delete (reduce add-deleted-group uchanges))] + [group rchanges uchanges])) (defn prepare-remove-group @@ -138,10 +139,13 @@ (let [shapes (:shapes group) parent-id (cp/get-parent (:id group) objects) parent (get objects parent-id) - index-in-parent (->> (:shapes parent) - (map-indexed vector) - (filter #(#{(:id group)} (second %))) - (ffirst)) + + index-in-parent + (->> (:shapes parent) + (map-indexed vector) + (filter #(#{(:id group)} (second %))) + (ffirst)) + rchanges [{:type :mov-objects :page-id page-id :parent-id parent-id @@ -223,39 +227,41 @@ [(first shapes) [] []] (prepare-create-group objects page-id shapes "Group-1" true)) - rchanges (d/concat rchanges - [{:type :mod-obj - :page-id page-id - :id (:id group) - :operations [{:type :set - :attr :masked-group? - :val true} - {:type :set - :attr :selrect - :val (-> shapes first :selrect)} - {:type :set - :attr :points - :val (-> shapes first :points)} - {:type :set - :attr :transform - :val (-> shapes first :transform)} - {:type :set - :attr :transform-inverse - :val (-> shapes first :transform-inverse)}]} - {:type :reg-objects - :page-id page-id - :shapes [(:id group)]}]) + rchanges (d/concat-vec + rchanges + [{:type :mod-obj + :page-id page-id + :id (:id group) + :operations [{:type :set + :attr :masked-group? + :val true} + {:type :set + :attr :selrect + :val (-> shapes first :selrect)} + {:type :set + :attr :points + :val (-> shapes first :points)} + {:type :set + :attr :transform + :val (-> shapes first :transform)} + {:type :set + :attr :transform-inverse + :val (-> shapes first :transform-inverse)}]} + {:type :reg-objects + :page-id page-id + :shapes [(:id group)]}]) - uchanges (conj uchanges - {:type :mod-obj - :page-id page-id - :id (:id group) - :operations [{:type :set - :attr :masked-group? - :val nil}]} - {:type :reg-objects - :page-id page-id - :shapes [(:id group)]})] + uchanges (d/concat-vec + uchanges + {:type :mod-obj + :page-id page-id + :id (:id group) + :operations [{:type :set + :attr :masked-group? + :val nil}]} + {:type :reg-objects + :page-id page-id + :shapes [(:id group)]})] (rx/of (dch/commit-changes {:redo-changes rchanges :undo-changes uchanges diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 9ba3a9a79e..e6c50d055b 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -666,14 +666,14 @@ (dwlh/generate-sync-file file-id :typographies library-id state)] xf-fcat (comp (remove nil?) (map first) (mapcat identity)) - rchanges (d/concat [] - (sequence xf-fcat library-changes) - (sequence xf-fcat file-changes)) + rchanges (d/concat-vec + (sequence xf-fcat library-changes) + (sequence xf-fcat file-changes)) xf-scat (comp (remove nil?) (map second) (mapcat identity)) - uchanges (d/concat [] - (sequence xf-scat library-changes) - (sequence xf-scat file-changes))] + uchanges (d/concat-vec + (sequence xf-scat library-changes) + (sequence xf-scat file-changes))] (log/debug :msg "SYNC-FILE finished" :js/rchanges (log-changes rchanges @@ -720,8 +720,8 @@ (let [file (dwlh/get-file state file-id) [rchanges1 uchanges1] (dwlh/generate-sync-file file-id :components library-id state) [rchanges2 uchanges2] (dwlh/generate-sync-library file-id :components library-id state) - rchanges (d/concat rchanges1 rchanges2) - uchanges (d/concat uchanges1 uchanges2)] + rchanges (d/concat-vec rchanges1 rchanges2) + uchanges (d/concat-vec uchanges1 uchanges2)] (when rchanges (log/debug :msg "SYNC-FILE (2nd stage) finished" :js/rchanges (log-changes rchanges diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index 53d8cf9a26..48a77a9e9e 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -54,8 +54,8 @@ (defn concat-changes [[rchanges1 uchanges1] [rchanges2 uchanges2]] - [(d/concat rchanges1 rchanges2) - (d/concat uchanges1 uchanges2)]) + [(d/concat-vec rchanges1 rchanges2) + (d/concat-vec uchanges1 uchanges2)]) (defn get-local-file [state] @@ -134,6 +134,10 @@ [(first shapes) [] []] (dwg/prepare-create-group objects page-id shapes "Component-1" true)) + ;; Asserts for documentation purposes + _ (us/assert vector? rchanges) + _ (us/assert vector? uchanges) + [new-shape new-shapes updated-shapes] (make-component-shape group objects file-id) @@ -288,8 +292,8 @@ state (cp/make-container page :page))] (recur (next pages) - (d/concat rchanges page-rchanges) - (d/concat uchanges page-uchanges))) + (into rchanges page-rchanges) + (into uchanges page-uchanges))) [rchanges uchanges])))) (defn generate-sync-library @@ -315,8 +319,8 @@ (cp/make-container local-component :component))] (recur (next local-components) - (d/concat rchanges comp-rchanges) - (d/concat uchanges comp-uchanges))) + (into rchanges comp-rchanges) + (into uchanges comp-uchanges))) [rchanges uchanges])))) (defn- generate-sync-container @@ -341,8 +345,8 @@ container shape)] (recur (next shapes) - (d/concat rchanges shape-rchanges) - (d/concat uchanges shape-uchanges))) + (into rchanges shape-rchanges) + (into uchanges shape-uchanges))) [rchanges uchanges])))) (defn- has-asset-reference-fn @@ -438,7 +442,7 @@ :fill-color-ref-id nil :fill-color-ref-file nil)))] (generate-sync-text-shape shape container update-node)) - (loop [attrs (seq color-sync-attrs) + (loop [attrs (seq color-sync-attrs) roperations [] uoperations []] (let [[attr-ref-id attr-ref-file color-attr attr] (first attrs)] @@ -490,8 +494,8 @@ :val (get shape attr-ref-file) :ignore-touched true}])] (recur (next attrs) - (concat roperations roperations') - (concat uoperations uoperations')))))))))) + (into roperations roperations') + (into uoperations uoperations')))))))))) (defmethod generate-sync-shape :typographies [_ library-id state container shape] @@ -734,8 +738,8 @@ moved false)] - [(d/concat rchanges child-rchanges) - (d/concat uchanges child-uchanges)]))) + [(d/concat-vec rchanges child-rchanges) + (d/concat-vec uchanges child-uchanges)]))) (defn generate-sync-shape-inverse "Generate changes to update the component a shape is linked to, from @@ -862,8 +866,8 @@ rchanges (mapv check-local rchanges) uchanges (mapv check-local uchanges)] - [(d/concat rchanges child-rchanges) - (d/concat uchanges child-uchanges)]))) + [(d/concat-vec rchanges child-rchanges) + (d/concat-vec uchanges child-uchanges)]))) ; ---- Operation generation helpers ---- @@ -963,33 +967,32 @@ update-new-shape update-original-shape) - rchanges (d/concat - (mapv (fn [shape'] - (make-change - container - (as-> {:type :add-obj - :id (:id shape') - :parent-id (:parent-id shape') - :index index - :ignore-touched true - :obj shape'} $ - (cond-> $ - (:frame-id shape') - (assoc :frame-id (:frame-id shape')))))) - new-shapes) - [(make-change - container - {:type :reg-objects - :shapes all-parents})]) + rchanges (d/concat-vec + (map (fn [shape'] + (make-change + container + (as-> {:type :add-obj + :id (:id shape') + :parent-id (:parent-id shape') + :index index + :ignore-touched true + :obj shape'} $ + (cond-> $ + (:frame-id shape') + (assoc :frame-id (:frame-id shape')))))) + new-shapes) + [(make-change + container + {:type :reg-objects + :shapes all-parents})]) - uchanges (d/concat - (mapv (fn [shape'] - (make-change - container - {:type :del-obj - :id (:id shape') - :ignore-touched true})) - new-shapes))] + uchanges (mapv (fn [shape'] + (make-change + container + {:type :del-obj + :id (:id shape') + :ignore-touched true})) + new-shapes)] (if (and (cp/touched-group? parent-shape :shapes-group) omit-touched?) empty-changes @@ -1024,47 +1027,46 @@ update-new-shape update-original-shape) - rchanges (d/concat - (mapv (fn [shape'] - {:type :add-obj - :id (:id shape') - :component-id (:id component) - :parent-id (:parent-id shape') - :index index - :ignore-touched true - :obj shape'}) - new-shapes) - [{:type :reg-objects - :component-id (:id component) - :shapes all-parents}] - (mapv (fn [shape'] - {:type :mod-obj - :page-id (:id page) - :id (:id shape') - :operations [{:type :set - :attr :component-id - :val (:component-id shape')} - {:type :set - :attr :component-file - :val (:component-file shape')} - {:type :set - :attr :component-root? - :val (:component-root? shape')} - {:type :set - :attr :shape-ref - :val (:shape-ref shape')} - {:type :set - :attr :touched - :val (:touched shape')}]}) - updated-shapes)) + rchanges (d/concat-vec + (map (fn [shape'] + {:type :add-obj + :id (:id shape') + :component-id (:id component) + :parent-id (:parent-id shape') + :index index + :ignore-touched true + :obj shape'}) + new-shapes) + [{:type :reg-objects + :component-id (:id component) + :shapes all-parents}] + (map (fn [shape'] + {:type :mod-obj + :page-id (:id page) + :id (:id shape') + :operations [{:type :set + :attr :component-id + :val (:component-id shape')} + {:type :set + :attr :component-file + :val (:component-file shape')} + {:type :set + :attr :component-root? + :val (:component-root? shape')} + {:type :set + :attr :shape-ref + :val (:shape-ref shape')} + {:type :set + :attr :touched + :val (:touched shape')}]}) + updated-shapes)) - uchanges (d/concat - (mapv (fn [shape'] - {:type :del-obj - :id (:id shape') - :page-id (:id page) - :ignore-touched true}) - new-shapes))] + uchanges (mapv (fn [shape'] + {:type :del-obj + :id (:id shape') + :page-id (:id page) + :ignore-touched true}) + new-shapes)] [rchanges uchanges])) @@ -1102,13 +1104,13 @@ (:frame-id shape') (assoc :frame-id (:frame-id shape'))))))) - uchanges (d/concat - [(add-change (:id shape))] - (map add-change children) - [(make-change - container - {:type :reg-objects - :shapes (vec parents)})])] + uchanges (d/concat-vec + [(add-change (:id shape))] + (map add-change children) + [(make-change + container + {:type :reg-objects + :shapes (vec parents)})])] (if (and (cp/touched-group? parent :shapes-group) omit-touched?) empty-changes diff --git a/frontend/src/app/main/data/workspace/path/state.cljs b/frontend/src/app/main/data/workspace/path/state.cljs index 86ac1731ee..0b00dc0994 100644 --- a/frontend/src/app/main/data/workspace/path/state.cljs +++ b/frontend/src/app/main/data/workspace/path/state.cljs @@ -6,7 +6,6 @@ (ns app.main.data.workspace.path.state (:require - [app.common.data :as d] [app.common.path.shapes-to-path :as upsp])) (defn get-path-id @@ -19,11 +18,10 @@ [state & ks] (let [edit-id (get-in state [:workspace-local :edition]) page-id (:current-page-id state)] - (d/concat - (if edit-id - [:workspace-data :pages-index page-id :objects edit-id] - [:workspace-drawing :object]) - ks))) + (into (if edit-id + [:workspace-data :pages-index page-id :objects edit-id] + [:workspace-drawing :object]) + ks))) (defn get-path "Retrieves the location of the path object and additionaly can pass diff --git a/frontend/src/app/main/data/workspace/svg_upload.cljs b/frontend/src/app/main/data/workspace/svg_upload.cljs index 2b253738af..5cb469e1b9 100644 --- a/frontend/src/app/main/data/workspace/svg_upload.cljs +++ b/frontend/src/app/main/data/workspace/svg_upload.cljs @@ -409,8 +409,10 @@ :shapes [shape-id]}] ;; Careful! the undo changes are concatenated reversed (we undo in reverse order - changes [(d/concat rchs rch1 rch2) (d/concat uch1 uchs)] - unames (conj unames (:name shape)) + changes [(d/concat-vec rchs rch1 rch2) + (d/concat-vec uch1 uchs)] + unames (conj unames (:name shape)) + reducer-fn (partial add-svg-child-changes page-id objects selected frame-id shape-id svg-data)] (reduce reducer-fn [unames changes] (d/enumerate children))) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index d7574e3309..19c667d2c8 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -25,7 +25,6 @@ [cljs.spec.alpha :as s] [potok.core :as ptk])) - ;; -- Helpers -------------------------------------------------------- ;; For each of the 8 handlers gives the multiplier for resize @@ -123,8 +122,7 @@ (let [modifiers (or modifiers (get-in state [:workspace-local :modifiers] {})) page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) - - ids (->> ids (into #{} (remove #(get-in objects [% :blocked] false))))] + ids (into #{} (remove #(get-in objects [% :blocked] false)) ids)] (reduce (fn [state id] (update state :workspace-modifiers @@ -148,20 +146,19 @@ ptk/UpdateEvent (update [_ state] (let [objects (wsh/lookup-page-objects state) - id->obj #(get objects %) - get-children (fn [shape] (map id->obj (cp/get-children (:id shape) objects))) - - shapes (->> shapes (into [] (remove #(get % :blocked false)))) - - shapes (->> shapes (mapcat get-children) (concat shapes)) + shapes (->> shapes + (remove #(get % :blocked false)) + (mapcat (fn [shape] + (->> (cp/get-children (:id shape) objects) + (map #(get objects %))))) + (concat shapes)) update-shape (fn [modifiers shape] (let [rotate-modifiers (gsh/rotation-modifiers shape center angle)] (assoc-in modifiers [(:id shape) :modifiers] rotate-modifiers)))] - (-> state - (update :workspace-modifiers - #(reduce update-shape % shapes)))))))) + + (update state :workspace-modifiers #(reduce update-shape % shapes))))))) (defn- apply-modifiers [ids] @@ -169,11 +166,11 @@ (ptk/reify ::apply-modifiers ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - children-ids (->> ids (mapcat #(cp/get-children % objects))) - ids-with-children (d/concat [] children-ids ids) - object-modifiers (get state :workspace-modifiers) - ignore-tree (d/mapm #(get-in %2 [:modifiers :ignore-geometry?]) object-modifiers)] + (let [objects (wsh/lookup-page-objects state) + children-ids (->> ids (mapcat #(cp/get-children % objects))) + ids-with-children (d/concat-vec children-ids ids) + object-modifiers (get state :workspace-modifiers) + ignore-tree (d/mapm #(get-in %2 [:modifiers :ignore-geometry?]) object-modifiers)] (rx/of (dwu/start-undo-transaction) (dch/update-shapes @@ -423,7 +420,10 @@ (watch [_ state _] (let [page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) - ids (d/concat [] ids (mapcat #(cp/get-children % objects) ids))] + + ;; TODO: looks completly redundant operation because + ;; apply-modifiers already finds all children. + ids (d/concat-vec ids (mapcat #(cp/get-children % objects) ids))] (rx/of (apply-modifiers ids)))))) diff --git a/frontend/src/app/main/snap.cljs b/frontend/src/app/main/snap.cljs index 6021730ef5..743306a72b 100644 --- a/frontend/src/app/main/snap.cljs +++ b/frontend/src/app/main/snap.cljs @@ -168,9 +168,8 @@ (map between-snap)) ;; Search the minimum snap - snap-list (-> [] (d/concat lt-snap) (d/concat gt-snap) (d/concat between-snap)) - - min-snap (reduce best-snap ##Inf snap-list)] + snap-list (d/concat-vec lt-snap gt-snap between-snap) + min-snap (reduce best-snap ##Inf snap-list)] (if (mth/finite? min-snap) [0 min-snap] nil))) @@ -291,8 +290,7 @@ (set (keys other)))] (into {} (map (fn [key] - [key - (d/concat [] (get matches key []) (get other key []))])) + [key (d/concat-vec (get matches key []) (get other key []))])) keys)))] (-> matches diff --git a/frontend/src/app/main/ui/measurements.cljs b/frontend/src/app/main/ui/measurements.cljs index 4fc319c1f1..e4dea1db10 100644 --- a/frontend/src/app/main/ui/measurements.cljs +++ b/frontend/src/app/main/ui/measurements.cljs @@ -192,7 +192,7 @@ h-lines (->> (calculate-distance-lines (:x1 from) (:x2 from) (:x1 to) (:x2 to)) (map (fn [[start end]] [start fixed-y end fixed-y]))) - lines (d/concat [] v-lines h-lines) + lines (d/concat-vec v-lines h-lines) distance-line-stroke (/ distance-line-stroke zoom)] diff --git a/frontend/src/app/main/ui/settings/options.cljs b/frontend/src/app/main/ui/settings/options.cljs index e3b3aed6b4..c2317e32d3 100644 --- a/frontend/src/app/main/ui/settings/options.cljs +++ b/frontend/src/app/main/ui/settings/options.cljs @@ -6,7 +6,6 @@ (ns app.main.ui.settings.options (:require - [app.common.data :as d] [app.common.spec :as us] [app.main.data.messages :as dm] [app.main.data.users :as du] @@ -49,8 +48,8 @@ [:h2 (t locale "labels.language")] [:div.fields-row - [:& fm/select {:options (d/concat [{:label "Auto (browser)" :value ""}] - i18n/supported-locales) + [:& fm/select {:options (into [{:label "Auto (browser)" :value ""}] + i18n/supported-locales) :label (t locale "dashboard.select-ui-language") :default "" :name :lang}]] diff --git a/frontend/src/app/main/ui/shapes/filters.cljs b/frontend/src/app/main/ui/shapes/filters.cljs index 60ba3fee66..1fb272c69b 100644 --- a/frontend/src/app/main/ui/shapes/filters.cljs +++ b/frontend/src/app/main/ui/shapes/filters.cljs @@ -149,8 +149,7 @@ (defn shape->filters [shape] - (d/concat - [] + (d/concat-vec [{:id "BackgroundImageFix" :type :image-fix}] ;; Background blur won't work in current SVG specification diff --git a/frontend/src/app/main/ui/viewer/handoff/exports.cljs b/frontend/src/app/main/ui/viewer/handoff/exports.cljs index e866617f7f..bbdc65cecd 100644 --- a/frontend/src/app/main/ui/viewer/handoff/exports.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/exports.cljs @@ -53,7 +53,7 @@ (fn [index] (swap! exports (fn [exports] (let [[before after] (split-at index exports)] - (d/concat [] before (rest after))))))) + (d/concat-vec before (rest after))))))) on-scale-change (mf/use-callback diff --git a/frontend/src/app/main/ui/viewer/interactions.cljs b/frontend/src/app/main/ui/viewer/interactions.cljs index f4faa97fc2..f0534aa951 100644 --- a/frontend/src/app/main/ui/viewer/interactions.cljs +++ b/frontend/src/app/main/ui/viewer/interactions.cljs @@ -36,7 +36,7 @@ update-fn #(d/update-when %1 %2 assoc-in [:modifiers :displacement] modifier)] (->> (cp/get-children frame-id objects) - (d/concat [frame-id]) + (into [frame-id]) (reduce update-fn objects))))) diff --git a/frontend/src/app/main/ui/viewer/shapes.cljs b/frontend/src/app/main/ui/viewer/shapes.cljs index 53a574ea02..cff1ce87a2 100644 --- a/frontend/src/app/main/ui/viewer/shapes.cljs +++ b/frontend/src/app/main/ui/viewer/shapes.cljs @@ -7,7 +7,6 @@ (ns app.main.ui.viewer.shapes "The main container for a frame in viewer mode" (:require - [app.common.data :as d] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as geom] @@ -396,7 +395,7 @@ update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier) frame-id (:id frame) - modifier-ids (d/concat [frame-id] (cp/get-children frame-id objects)) + modifier-ids (into [frame-id] (cp/get-children frame-id objects)) objects (reduce update-fn objects modifier-ids) frame (assoc-in frame [:modifiers :displacement] modifier) 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 0330f101fc..2ccc1583da 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs @@ -6,7 +6,6 @@ (ns app.main.ui.workspace.shapes.path.editor (:require - [app.common.data :as d] [app.common.geom.point :as gpt] [app.common.geom.shapes.path :as gsp] [app.common.path.commands :as upc] @@ -166,9 +165,9 @@ :zoom zoom}]]) (mf/defc path-snap [{:keys [selected points zoom]}] - (let [ranges (mf/use-memo (mf/deps selected points) #(snap/create-ranges points selected)) + (let [ranges (mf/use-memo (mf/deps selected points) #(snap/create-ranges points selected)) snap-matches (snap/get-snap-delta-match selected ranges (/ 1 zoom)) - matches (d/concat [] (second (:x snap-matches)) (second (:y snap-matches)))] + matches (concat (second (:x snap-matches)) (second (:y snap-matches)))] [:g.snap-paths (for [[from to] matches] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs index 9dbe80aca5..0327912f42 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs @@ -75,7 +75,7 @@ (mf/deps shape) (fn [index] (let [[before after] (split-at index exports) - exports (d/concat [] before (rest after))] + exports (d/concat-vec before (rest after))] (st/emit! (udw/update-shape (:id shape) {:exports exports}))))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs index 5f55a9ab2e..b77caab13d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs @@ -68,17 +68,19 @@ (def root-attrs text-valign-attrs) (def paragraph-attrs - (d/concat text-align-attrs - text-direction-attrs)) + (d/concat-vec + text-align-attrs + text-direction-attrs)) (def text-attrs - (d/concat text-typography-attrs - text-font-attrs - text-spacing-attrs - text-decoration-attrs - text-transform-attrs)) + (d/concat-vec + text-typography-attrs + text-font-attrs + text-spacing-attrs + text-decoration-attrs + text-transform-attrs)) -(def attrs (d/concat #{} shape-attrs root-attrs paragraph-attrs text-attrs)) +(def attrs (d/concat-set shape-attrs root-attrs paragraph-attrs text-attrs)) (mf/defc text-align-options [{:keys [values on-change on-blur] :as props}] @@ -271,12 +273,12 @@ (fn [_] (let [setted-values (-> (d/without-nils values) (select-keys - (d/concat text-font-attrs - text-spacing-attrs - text-transform-attrs))) - typography (merge txt/default-typography setted-values) - typography (generate-typography-name typography) - id (uuid/next)] + (d/concat-vec text-font-attrs + text-spacing-attrs + text-transform-attrs))) + typography (merge txt/default-typography setted-values) + typography (generate-typography-name typography) + id (uuid/next)] (st/emit! (dwl/add-typography (assoc typography :id id) false)) (run! #(emit-update! % {:typography-ref-id id :typography-ref-file file-id}) ids))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs index bbad1e1694..5358238e21 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs @@ -183,7 +183,7 @@ (attrs/get-attrs-multi (txt/node-seq content) attrs))))] :children (let [children (->> (:shapes shape []) (map #(get objects %))) [new-ids new-values] (get-attrs children objects attr-type)] - [(d/concat ids new-ids) (merge-attrs values new-values)]) + [(d/concat-vec ids new-ids) (merge-attrs values new-values)]) [])))] (reduce extract-attrs [[] []] shapes))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs index 9acacb9774..5e77a90040 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs @@ -82,7 +82,7 @@ on-drop (mf/use-callback - (mf/deps id) + (mf/deps id index) (fn [side {:keys [id] :as data}] (let [index (if (= :bot side) (inc index) index)] (st/emit! (dw/relocate-page id index))))) diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs index b9df6b9839..b2e596e113 100644 --- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs @@ -6,7 +6,6 @@ (ns app.main.ui.workspace.viewport.hooks (:require - [app.common.data :as d] [app.common.geom.shapes :as gsh] [app.common.pages :as cp] [app.main.data.shortcuts :as dsc] @@ -162,10 +161,9 @@ remove-xfm (mapcat #(cp/get-parents % objects)) remove-id? (cond-> (into #{} remove-xfm selected) @ctrl? - (d/concat (filterv is-group? ids))) - - ids (->> ids (filterv (comp not remove-id?))) + (into (filter is-group?) ids)) + ids (filterv (comp not remove-id?) ids) hover-shape (get objects (first ids))] (reset! hover hover-shape) diff --git a/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs b/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs index a5c85499f9..aecd0b52f1 100644 --- a/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs @@ -163,12 +163,12 @@ show-candidate? #(check-in-set % distances) ;; Checks the distances between elements for distances that match the set of distances - distance-coincidences (d/concat (get-shapes-match show-candidate? lt-shapes) - (get-shapes-match show-candidate? gt-shapes)) + distance-coincidences (d/concat-vec + (get-shapes-match show-candidate? lt-shapes) + (get-shapes-match show-candidate? gt-shapes)) ;; Stores the distance candidates to be shown - distance-candidates (d/concat - #{} + distance-candidates (d/concat-set (map first distance-coincidences) (filter #(check-in-set % lt-distances) gt-distances) (filter #(check-in-set % gt-distances) lt-distances)) @@ -194,7 +194,7 @@ (filter #(show-distance? (distance-to-selrect %))) (map #(vector selrect (:selrect %)))) - segments-to-display (d/concat #{} other-shapes-segments selection-segments)] + segments-to-display (d/concat-set other-shapes-segments selection-segments)] segments-to-display)) (mf/defc shape-distance diff --git a/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs b/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs index 5fad2a5c1d..fd8a015e0e 100644 --- a/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs @@ -121,7 +121,7 @@ (rx/switch-map #(rx/combine-latest (get-snap :x %) (get-snap :y %))) (rx/map (fn [result] - (apply d/concat (seq result)))) + (apply d/concat-vec (seq result)))) (rx/subs #(let [rs (filter (fn [[_ snaps _]] (> (count snaps) 0)) %)] (reset! state rs))))] diff --git a/frontend/src/app/util/path/parser.cljs b/frontend/src/app/util/path/parser.cljs index 99e6435a52..6b0f50faca 100644 --- a/frontend/src/app/util/path/parser.cljs +++ b/frontend/src/app/util/path/parser.cljs @@ -60,14 +60,14 @@ param-list (extract-params cmd [[:x :number] [:y :number]])] - (d/concat [{:command :move-to - :relative relative - :params (first param-list)}] + (into [{:command :move-to + :relative relative + :params (first param-list)}] - (for [params (rest param-list)] - {:command :line-to - :relative relative - :params params})))) + (for [params (rest param-list)] + {:command :line-to + :relative relative + :params params})))) (defmethod parse-command "Z" [_] [{:command :close-path}]) @@ -259,7 +259,7 @@ (update :params merge (quadratic->curve prev-pos (gpt/point params) (upg/calculate-opposite-handler prev-pos prev-qc))))) result (if (= :elliptical-arc (:command command)) - (d/concat result (arc->beziers prev-pos command)) + (into result (arc->beziers prev-pos command)) (conj result command)) next-cc (case (:command orig-command) diff --git a/frontend/src/app/util/path/tools.cljs b/frontend/src/app/util/path/tools.cljs index 9f97ab666f..2293a297b4 100644 --- a/frontend/src/app/util/path/tools.cljs +++ b/frontend/src/app/util/path/tools.cljs @@ -304,7 +304,7 @@ [content points] (let [segments-set (into #{} - (map (fn [{:keys [start end]}] [start end])) + (juxt :start :end) (get-segments content points)) create-line-command (fn [point other] @@ -318,7 +318,7 @@ (flatten) (into []))] - (d/concat content new-content))) + (into content new-content))) (defn separate-nodes diff --git a/frontend/src/app/util/svg.cljs b/frontend/src/app/util/svg.cljs index 932f900295..5f76d97185 100644 --- a/frontend/src/app/util/svg.cljs +++ b/frontend/src/app/util/svg.cljs @@ -630,8 +630,7 @@ (defn find-node-references [node] (let [current (->> (find-attr-references (:attrs node)) (into #{})) children (->> (:content node) (map find-node-references) (flatten) (into #{}))] - (-> (d/concat current children) - (vec)))) + (vec (into current children)))) (defn find-def-references [defs references] (loop [result (into #{} references) @@ -653,7 +652,7 @@ (let [node (get defs to-check) new-refs (find-node-references node) pending (concat pending new-refs)] - (recur (d/concat result new-refs) + (recur (into result new-refs) (conj checked? to-check) (first pending) (rest pending)))))) diff --git a/frontend/src/app/worker/export.cljs b/frontend/src/app/worker/export.cljs index 02fae88fee..ba4b01cef0 100644 --- a/frontend/src/app/worker/export.cljs +++ b/frontend/src/app/worker/export.cljs @@ -292,7 +292,7 @@ :file-id (:component-file shape)}) (= :text (:type shape)) - (d/concat (get-text-refs (:content shape)))))] + (into (get-text-refs (:content shape)))))] (->> (get-in file [:data :pages-index]) (vals) diff --git a/frontend/src/app/worker/selection.cljs b/frontend/src/app/worker/selection.cljs index 64217e0140..dc05e15321 100644 --- a/frontend/src/app/worker/selection.cljs +++ b/frontend/src/app/worker/selection.cljs @@ -66,7 +66,7 @@ changed-ids (into #{} (comp (filter #(not= % uuid/zero)) (filter changes?) - (mapcat #(d/concat [%] (cp/get-children % new-objects)))) + (mapcat #(into [%] (cp/get-children % new-objects)))) (set/union (set (keys old-objects)) (set (keys new-objects)))) diff --git a/frontend/src/app/worker/snaps.cljs b/frontend/src/app/worker/snaps.cljs index a4926731b5..66a4dff837 100644 --- a/frontend/src/app/worker/snaps.cljs +++ b/frontend/src/app/worker/snaps.cljs @@ -22,13 +22,11 @@ (let [points (when-not (:hidden shape) (snap/shape-snap-points shape)) shape-data (->> points (mapv #(vector % (:id shape))))] (if (= (:id shape) frame-id) - (d/concat - shape-data - - ;; The grid points are only added by the "root" of the coord-dat - (->> (gg/grid-snap-points shape coord) - (map #(vector % :layout)))) + (into shape-data + ;; The grid points are only added by the "root" of the coord-dat + (->> (gg/grid-snap-points shape coord) + (map #(vector % :layout)))) shape-data)))) (defn- add-coord-data From f8cecfd61f4cc2e8db3847cbc48a2c04a8899d92 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 2 Dec 2021 15:30:26 +0100 Subject: [PATCH 2/2] :bug: Fix unexpected behavior of grid options on right sidebar. --- common/src/app/common/pages/common.cljc | 2 +- common/src/app/common/pages/migrations.cljc | 13 ++ common/src/app/common/types/page_options.cljc | 5 +- .../partials/sidebar-element-options.scss | 6 +- .../main/ui/components/editable_select.cljs | 48 +++-- .../app/main/ui/components/numeric_input.cljs | 54 +++-- .../sidebar/options/menus/frame_grid.cljs | 195 ++++++++++-------- .../sidebar/options/rows/input_row.cljs | 32 ++- frontend/src/app/util/simple_math.cljs | 8 +- 9 files changed, 204 insertions(+), 159 deletions(-) diff --git a/common/src/app/common/pages/common.cljc b/common/src/app/common/pages/common.cljc index d97c9f05c6..53c7157833 100644 --- a/common/src/app/common/pages/common.cljc +++ b/common/src/app/common/pages/common.cljc @@ -8,7 +8,7 @@ (:require [app.common.uuid :as uuid])) -(def file-version 11) +(def file-version 12) (def default-color "#b1b2b5") ;; $color-gray-20 (def root uuid/zero) diff --git a/common/src/app/common/pages/migrations.cljc b/common/src/app/common/pages/migrations.cljc index 104e1fe4c5..dd7d232681 100644 --- a/common/src/app/common/pages/migrations.cljc +++ b/common/src/app/common/pages/migrations.cljc @@ -268,3 +268,16 @@ (update page :objects #(d/mapm (partial update-object %) %)))] (update data :pages-index #(d/mapm update-page %)))) + + +(defmethod migrate 12 + [data] + (letfn [(update-grid [_key grid] + (cond-> grid + (= :auto (:size grid)) + (assoc :size nil))) + + (update-page [_id page] + (d/update-in-when page [:options :saved-grids] #(d/mapm update-grid %)))] + + (update data :pages-index #(d/mapm update-page %)))) diff --git a/common/src/app/common/types/page_options.cljc b/common/src/app/common/types/page_options.cljc index c15258edac..968be643c8 100644 --- a/common/src/app/common/types/page_options.cljc +++ b/common/src/app/common/types/page_options.cljc @@ -15,11 +15,12 @@ (s/def :artboard-grid.color/color ::us/string) (s/def :artboard-grid.color/opacity ::us/safe-number) -(s/def :artboard-grid/size ::us/safe-integer) +(s/def :artboard-grid/size (s/nilable ::us/safe-integer)) +(s/def :artboard-grid/item-length (s/nilable ::us/safe-number)) + (s/def :artboard-grid/color (s/keys :req-un [:artboard-grid.color/color :artboard-grid.color/opacity])) (s/def :artboard-grid/type #{:stretch :left :center :right}) -(s/def :artboard-grid/item-length (s/nilable ::us/safe-integer)) (s/def :artboard-grid/gutter (s/nilable ::us/safe-integer)) (s/def :artboard-grid/margin (s/nilable ::us/safe-integer)) diff --git a/frontend/resources/styles/main/partials/sidebar-element-options.scss b/frontend/resources/styles/main/partials/sidebar-element-options.scss index ef8fecf0b4..27d8b07fbe 100644 --- a/frontend/resources/styles/main/partials/sidebar-element-options.scss +++ b/frontend/resources/styles/main/partials/sidebar-element-options.scss @@ -406,7 +406,7 @@ border: 1px solid transparent; position: relative; height: 38px; - margin-right: $size-2; + // margin-left: $size-2; max-height: 30px; position: relative; width: 60%; @@ -494,12 +494,10 @@ .editable-select svg { fill: $color-gray-40; } - .dropdown-button { - top: 4px; - } .editable-select.input-option .input-text { padding: 0; padding-top: 0.18rem; + padding-left: 0.25rem; } .input-element { diff --git a/frontend/src/app/main/ui/components/editable_select.cljs b/frontend/src/app/main/ui/components/editable_select.cljs index 49cea928f6..b11e4159ab 100644 --- a/frontend/src/app/main/ui/components/editable_select.cljs +++ b/frontend/src/app/main/ui/components/editable_select.cljs @@ -16,7 +16,8 @@ [app.util.timers :as timers] [rumext.alpha :as mf])) -(mf/defc editable-select [{:keys [value type options class on-change placeholder on-blur] :as params}] +(mf/defc editable-select + [{:keys [value type options class on-change placeholder on-blur] :as params}] (let [state (mf/use-state {:id (uuid/next) :is-open? false :current-value value @@ -42,20 +43,23 @@ (when on-blur (on-blur)))) as-key-value (fn [item] (if (map? item) [(:value item) (:label item)] [item item])) - - labels-map (into {} (->> options (map as-key-value))) - + labels-map (into {} (map as-key-value) options) value->label (fn [value] (get labels-map value value)) - set-value (fn [value] - (swap! state assoc :current-value value) - (when on-change (on-change value))) + set-value + (fn [value] + (swap! state assoc :current-value value) + (when on-change (on-change value))) - handle-change-input (fn [event] - (let [value (-> event dom/get-target dom/get-value) - value (-> (or (d/parse-double value) value) - (math/precision 2))] - (set-value value))) + ;; TODO: why this method supposes that all editable select + ;; works with numbers? + + handle-change-input + (fn [event] + (let [value (-> event dom/get-target dom/get-value) + value (-> (or (d/parse-double value) value) + (math/precision 2))] + (set-value value))) on-node-load (fn [node] @@ -133,7 +137,7 @@ [:div.editable-select {:class class :ref on-node-load} - [:input.input-text {:value (or (-> @state :current-value value->label) "") + [:input.input-text {:value (or (some-> @state :current-value value->label) "") :on-change handle-change-input :on-key-down handle-key-down :on-focus handle-focus @@ -149,12 +153,12 @@ :left (:left @state) :bottom (:bottom @state)}} (for [[index item] (map-indexed vector options)] - (cond - (= :separator item) [:hr {:key (str (:id @state) "-" index)}] - :else (let [[value label] (as-key-value item)] - [:li.checked-element - {:key (str (:id @state) "-" index) - :class (when (= value (-> @state :current-value)) "is-selected") - :on-click (select-item value)} - [:span.check-icon i/tick] - [:span label]])))]]])) + (if (= :separator item) + [:hr {:key (str (:id @state) "-" index)}] + (let [[value label] (as-key-value item)] + [:li.checked-element + {:key (str (:id @state) "-" index) + :class (when (= value (-> @state :current-value)) "is-selected") + :on-click (select-item value)} + [:span.check-icon i/tick] + [:span label]])))]]])) diff --git a/frontend/src/app/main/ui/components/numeric_input.cljs b/frontend/src/app/main/ui/components/numeric_input.cljs index 47595beac7..33e0ef881c 100644 --- a/frontend/src/app/main/ui/components/numeric_input.cljs +++ b/frontend/src/app/main/ui/components/numeric_input.cljs @@ -15,6 +15,11 @@ [app.util.simple-math :as sm] [rumext.alpha :as mf])) +(defn num? [val] + (and (number? val) + (not (math/nan? val)) + (math/finite? val))) + (mf/defc numeric-input {::mf/wrap-props false ::mf/forward-ref true} @@ -25,32 +30,31 @@ wrap-value? (obj/get props "data-wrap") on-change (obj/get props "onChange") title (obj/get props "title") + default-val (obj/get props "default" 0) ;; We need a ref pointing to the input dom element, but the user ;; of this component may provide one (that is forwarded here). ;; So we use the external ref if provided, and the local one if not. - local-ref (mf/use-ref) - ref (or external-ref local-ref) + local-ref (mf/use-ref) + ref (or external-ref local-ref) - value (d/parse-integer value-str 0) + ;; This `value` represents the previous value and is used as + ;; initil value for the simple math expression evaluation. + value (d/parse-integer value-str default-val) - min-val (cond - (number? min-val-str) - min-val-str + min-val (cond + (number? min-val-str) + min-val-str - (string? min-val-str) - (d/parse-integer min-val-str)) + (string? min-val-str) + (d/parse-integer min-val-str)) - max-val (cond - (number? max-val-str) - max-val-str + max-val (cond + (number? max-val-str) + max-val-str - (string? max-val-str) - (d/parse-integer max-val-str)) - - num? (fn [val] (and (number? val) - (not (math/nan? val)) - (math/finite? val))) + (string? max-val-str) + (d/parse-integer max-val-str)) parse-value (mf/use-callback @@ -82,10 +86,9 @@ (mf/use-callback (mf/deps on-change update-input value) (fn [new-value] - (when (and (some? new-value) (not= new-value value) (some? on-change)) + (when (and (not= new-value value) (some? on-change)) (on-change new-value)) - (when (some? new-value) - (update-input new-value)))) + (update-input new-value))) set-delta (mf/use-callback @@ -143,10 +146,10 @@ (mf/use-callback (mf/deps parse-value apply-value update-input) (fn [_] - (let [new-value (parse-value)] + (let [new-value (or (parse-value) default-val)] (if new-value (apply-value new-value) - (update-input value-str))))) + (update-input new-value))))) props (-> props (obj/without ["value" "onChange"]) @@ -159,12 +162,5 @@ (obj/set! "onKeyDown" handle-key-down) (obj/set! "onBlur" handle-blur))] - (mf/use-effect - (mf/deps value-str) - (fn [] - (when-let [input-node (mf/ref-val ref)] - (when-not (dom/active? input-node) - (dom/set-value! input-node value-str))))) - [:> :input props])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs index e5a4cbb29f..b7933d320b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs @@ -16,8 +16,7 @@ [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.common :refer [advanced-options]] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] - [app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]] - [app.util.data :as d] + [app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row input-row-v2]] [app.util.geom.grid :as gg] [app.util.i18n :as i18n :refer [tr]] [okulary.core :as l] @@ -27,90 +26,101 @@ (l/derived :saved-grids refs/workspace-page-options)) (defn- get-size-options [] - [{:value :auto :label (tr "workspace.options.grid.auto")} + [{:value nil :label (tr "workspace.options.grid.auto")} :separator 18 12 10 8 6 4 3 2]) (mf/defc grid-options - [{:keys [grid frame default-grid-params on-change on-remove on-save-grid]}] - (let [size-options (get-size-options) - state (mf/use-state {:show-advanced-options false}) + {::mf/wrap [mf/memo]} + [{:keys [shape-id index grid frame-width frame-height default-grid-params]}] + (let [on-change (mf/use-fn (mf/deps shape-id index) #(st/emit! (dw/set-frame-grid shape-id index %))) + on-remove (mf/use-fn (mf/deps shape-id index) #(st/emit! (dw/remove-frame-grid shape-id index))) + on-save-default (mf/use-fn #(st/emit! (dw/set-default-grid (:type %) (:params %)))) + + size-options (mf/use-memo get-size-options) + state (mf/use-state {:show-advanced-options false}) + {:keys [type display params]} grid toggle-advanced-options - #(swap! state update :show-advanced-options not) + (mf/use-fn #(swap! state update :show-advanced-options not)) handle-toggle-visibility - (fn [_] - (when on-change - (on-change (update grid :display #(if (nil? %) false (not %)))))) - - handle-remove-grid - (fn [_] - (when on-remove (on-remove))) + (mf/use-fn + (mf/deps grid) + (fn [_] + (on-change (update grid :display #(if (nil? %) false (not %)))))) handle-change-type - (fn [grid-type] - (let [defaults (grid-type default-grid-params)] - (when on-change - (on-change (assoc grid - :type grid-type - :params defaults))))) - + (mf/use-fn + (mf/deps grid) + (fn [grid-type] + (let [defaults (grid-type default-grid-params)] + (on-change (assoc grid + :type grid-type + :params defaults))))) handle-change - (fn [& keys] + (fn [& keys-path] (fn [value] - (when on-change - (on-change (assoc-in grid keys value))))) + (on-change (assoc-in grid keys-path value)))) + ;; TODO: remove references to :auto handle-change-size - (fn [size] - (let [{:keys [margin gutter item-length]} (:params grid) - frame-length (if (= :column (:type grid)) (:width frame) (:height frame)) - item-length (if (or (nil? size) (= :auto size)) - (-> (gg/calculate-default-item-length frame-length margin gutter) - (mth/precision 2)) - item-length)] - (when on-change - (on-change (-> grid - (assoc-in [:params :size] size) - (assoc-in [:params :item-length] item-length)))))) + (mf/use-fn + (mf/deps grid) + (fn [size] + (let [{:keys [margin gutter item-length]} (:params grid) + frame-length (if (= :column (:type grid)) frame-width frame-height) + item-length (if (nil? size) + (-> (gg/calculate-default-item-length frame-length margin gutter) + (mth/precision 2)) + item-length)] + + (-> grid + (update :params assoc :size size :item-length item-length) + (on-change))))) handle-change-item-length - (fn [item-length] - (let [size (get-in grid [:params :size]) - size (if (and (nil? item-length) (or (nil? size) (= :auto size))) 12 size)] - (when on-change - (on-change (-> grid - (assoc-in [:params :size] size) - (assoc-in [:params :item-length] item-length)))))) + (mf/use-fn + (mf/deps grid) + (fn [item-length] + (let [item-length (if (zero? item-length) nil item-length) + size (get-in grid [:params :size]) + size (if (and (nil? item-length) (nil? size)) 12 size)] + (-> grid + (update :params assoc :size size :item-length item-length) + (on-change))))) handle-change-color - (fn [color] - (when on-change - (on-change (assoc-in grid [:params :color] color)))) + (mf/use-fn + (mf/deps grid) + (fn [color] + (-> grid + (update :params assoc :color color) + (on-change)))) handle-detach-color - (fn [] - (when on-change - (on-change (-> grid - (d/dissoc-in [:params :color :id]) - (d/dissoc-in [:params :color :file-id]))))) + (mf/use-fn + (mf/deps grid) + (fn [] + (-> grid + (update-in [:params :color] dissoc :id :file-id) + (on-change)))) handle-use-default - (fn [] - (let [params ((:type grid) default-grid-params) - color (or (get-in params [:color :value]) (get-in params [:color :color])) - params (-> params - (assoc-in [:color :color] color) - (update :color dissoc :value))] - (when on-change - (on-change (assoc grid :params params))))) + (mf/use-fn + (mf/deps grid) + (fn [] + (let [params ((:type grid) default-grid-params) + color (or (get-in params [:color :value]) (get-in params [:color :color])) + params (-> params + (assoc-in [:color :color] color) + (update :color dissoc :value))] + (when on-change + (on-change (assoc grid :params params)))))) handle-set-as-default - (fn [] - (when on-save-grid - (on-save-grid grid))) + (mf/use-fn (mf/deps grid) #(on-save-default grid)) is-default (= (->> grid :params) (->> grid :type default-grid-params)) @@ -122,21 +132,23 @@ [:button.custom-button {:class (when open? "is-active") :on-click toggle-advanced-options} i/actions] - [:& select {:class "flex-grow" - :default-value type - :options [{:value :square :label (tr "workspace.options.grid.square")} - {:value :column :label (tr "workspace.options.grid.column")} - {:value :row :label (tr "workspace.options.grid.row")}] - :on-change handle-change-type}] + [:& select + {:class "flex-grow" + :default-value type + :options [{:value :square :label (tr "workspace.options.grid.square")} + {:value :column :label (tr "workspace.options.grid.column")} + {:value :row :label (tr "workspace.options.grid.row")}] + :on-change handle-change-type}] (if (= type :square) [:div.input-element.pixels {:title (tr "workspace.options.size")} [:> numeric-input {:min 1 + :value (or (:size params) "") :no-validate true - :value (:size params) :on-change (handle-change :params :size)}]] + [:& editable-select {:value (:size params) - :type (when (number? (:size params)) "number" ) + :type "number" :class "input-option" :min 1 :options size-options @@ -145,10 +157,9 @@ [:div.grid-option-main-actions [:button.custom-button {:on-click handle-toggle-visibility} (if display i/eye i/eye-closed)] - [:button.custom-button {:on-click handle-remove-grid} i/minus]]] + [:button.custom-button {:on-click on-remove} i/minus]]] - [:& advanced-options {:visible? open? - :on-close toggle-advanced-options} + [:& advanced-options {:visible? open? :on-close toggle-advanced-options} [:button.custom-button {:on-click toggle-advanced-options} i/actions] (when (= :square type) [:& input-row {:label (tr "workspace.options.grid.params.size") @@ -190,13 +201,16 @@ :on-change (handle-change :params :type)}]) (when (#{:row :column} type) - [:& input-row {:label (if (= :row type) - (tr "workspace.options.grid.params.height") - (tr "workspace.options.grid.params.width")) - :class "pixels" - :placeholder "Auto" - :value (or (:item-length params) "") - :on-change handle-change-item-length}]) + [:& input-row-v2 + {:class "pixels" + :label (if (= :row type) + (tr "workspace.options.grid.params.height") + (tr "workspace.options.grid.params.width"))} + [:> numeric-input + {:placeholder "Auto" + :value (or (:item-length params) "") + :default nil + :on-change handle-change-item-length}]]) (when (#{:row :column} type) [:* @@ -226,11 +240,9 @@ (mf/defc frame-grid [{:keys [shape]}] (let [id (:id shape) - default-grid-params (merge dw/default-grid-params (mf/deref workspace-saved-grids)) - handle-create-grid #(st/emit! (dw/add-frame-grid id)) - handle-remove-grid (fn [index] #(st/emit! (dw/remove-frame-grid id index))) - handle-edit-grid (fn [index] #(st/emit! (dw/set-frame-grid id index %))) - handle-save-grid (fn [grid] (st/emit! (dw/set-default-grid (:type grid) (:params grid))))] + saved-grids (mf/deref workspace-saved-grids) + default-grid-params (mf/use-memo (mf/deps saved-grids) #(merge dw/default-grid-params saved-grids)) + handle-create-grid (mf/use-fn (mf/deps id) #(st/emit! (dw/add-frame-grid id)))] [:div.element-set [:div.element-set-title [:span (tr "workspace.options.grid.title")] @@ -239,12 +251,13 @@ (when (seq (:grids shape)) [:div.element-set-content (for [[index grid] (map-indexed vector (:grids shape))] - [:& grid-options {:key (str (:id shape) "-" index) - :grid grid - :default-grid-params default-grid-params - :frame shape - :on-change (handle-edit-grid index) - :on-remove (handle-remove-grid index) - :on-save-grid handle-save-grid}])])])) + [:& grid-options {:key (str id "-" index) + :shape-id id + :grid grid + :index index + :frame-width (:width shape) + :frame-height (:height shape) + :default-grid-params default-grid-params + }])])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs index 9ab071389b..5adc576429 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs @@ -9,6 +9,7 @@ [app.main.ui.components.editable-select :refer [editable-select]] [app.main.ui.components.numeric-input :refer [numeric-input]] [app.main.ui.components.select :refer [select]] + [app.util.object :as obj] [rumext.alpha :as mf])) (mf/defc input-row [{:keys [label options value class min max on-change type placeholder]}] @@ -27,7 +28,7 @@ [:& editable-select {:value value :class "input-option" :options options - :type (when (number? value) "number") + :type "number" :min min :max max :placeholder placeholder @@ -38,9 +39,28 @@ :class "input-text" :on-change on-change} ] - [:> numeric-input {:placeholder placeholder - :min min - :max max - :on-change on-change - :value (or value "")}])]]) + [:> numeric-input + {:placeholder placeholder + :min min + :max max + :on-change on-change + :value (or value "")}])]]) + + +;; NOTE: (by niwinz) this is a new version of input-row, I didn't +;; touched the original one because it is used in many sites and I +;; don't have intention to refactor all the code right now. We should +;; consider to use the new one and once we have migrated all to the +;; new component, we can proceed to rename it and delete the old one. + +(mf/defc input-row-v2 + {::mf/wrap-props false} + [props] + (let [label (obj/get props "label") + class (obj/get props "class") + children (obj/get props "children")] + [:div.row-flex.input-row + [:span.element-set-subtitle label] + [:div.input-element {:class class} + children]])) diff --git a/frontend/src/app/util/simple_math.cljs b/frontend/src/app/util/simple_math.cljs index 34d476d455..ef45032949 100644 --- a/frontend/src/app/util/simple_math.cljs +++ b/frontend/src/app/util/simple_math.cljs @@ -28,9 +28,8 @@ (let [token (first tree) args (rest tree)] (case token - :opt-expr - (if (empty? args) 0 (interpret (first args) init-value)) + (if (empty? args) nil (interpret (first args) init-value)) :expr (if (index-of "+-*/" (first args)) @@ -87,8 +86,9 @@ (defn expr-eval [expr init-value] (s/assert string? expr) - (s/assert number? init-value) - (let [result (parser expr)] + (let [result (parser expr) + init-value (or init-value 0)] + (s/assert number? init-value) (if-not (insta/failure? result) (interpret result init-value) (let [text (:text result)