diff --git a/CHANGES.md b/CHANGES.md index 815e44385e..1bfc2aef65 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -55,6 +55,7 @@ - Fix ghost shapes after sync groups in components [Taiga #4649](https://tree.taiga.io/project/penpot/issue/4649) - Fix layer orders messed up on move, group, reparent and undo [Github #2672](https://github.com/penpot/penpot/issues/2672) - 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) ## 1.16.2-beta diff --git a/common/src/app/common/pages/changes_builder.cljc b/common/src/app/common/pages/changes_builder.cljc index e85445cc41..af40ae00cb 100644 --- a/common/src/app/common/pages/changes_builder.cljc +++ b/common/src/app/common/pages/changes_builder.cljc @@ -378,14 +378,16 @@ add-undo-change-parent (fn [change-set id] - (let [shape (get objects id)] + (let [shape (get objects id) + prev-sibling (cph/get-prev-sibling objects (:id shape))] (d/preconj change-set {:type :mov-objects :page-id page-id :parent-id (:parent-id shape) :shapes [id] - :index (cph/get-position-on-parent objects id) + :after-shape prev-sibling + :index 0 :ignore-touched true})))] (-> changes diff --git a/frontend/resources/images/icons/bug.svg b/frontend/resources/images/icons/bug.svg new file mode 100644 index 0000000000..2904d3122f --- /dev/null +++ b/frontend/resources/images/icons/bug.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/styles/main/partials/sidebar.scss b/frontend/resources/styles/main/partials/sidebar.scss index 7979ba2e16..ffae5942e6 100644 --- a/frontend/resources/styles/main/partials/sidebar.scss +++ b/frontend/resources/styles/main/partials/sidebar.scss @@ -360,12 +360,16 @@ button.collapse-sidebar { overflow: hidden; } -.shortcuts { - .shortcuts-header { +.shortcuts, +.debug-panel { + .shortcuts-header, + .debug-panel-header { display: flex; height: 40px; background-color: $color-gray-60; - .shortcuts-title { + + .shortcuts-title, + .debug-panel-title { color: $color-white; font-size: $fs12; display: flex; @@ -379,7 +383,9 @@ button.collapse-sidebar { fill: $color-gray-20; } } - .shortcuts-close-button { + + .shortcuts-close-button, + .debug-panel-close-button { display: flex; justify-content: center; background-color: transparent; @@ -547,3 +553,35 @@ button.collapse-sidebar { font-size: $fs12; } } + +.debug-panel { + .debug-panel-inner { + padding: 8px; + } + .debug-option { + display: flex; + gap: 8px; + margin: 4px 0; + cursor: pointer; + + label { + font-size: 80%; + cursor: pointer; + } + + svg { + width: 15px; + height: 15px; + background: white; + } + + &:hover { + svg { + stroke: var(--color-primary); + } + label { + color: var(--color-primary); + } + } + } +} diff --git a/frontend/src/app/main.cljs b/frontend/src/app/main.cljs index 5831edea8c..678eaf3aa4 100644 --- a/frontend/src/app/main.cljs +++ b/frontend/src/app/main.cljs @@ -81,7 +81,7 @@ (init-ui) (st/emit! (initialize))) -(defn reinit +(defn ^:export reinit [] (mf/unmount (dom/get-element "app")) (mf/unmount (dom/get-element "modal")) diff --git a/frontend/src/app/main/data/workspace/drawing/box.cljs b/frontend/src/app/main/data/workspace/drawing/box.cljs index 39971af7c4..54e5456fe4 100644 --- a/frontend/src/app/main/data/workspace/drawing/box.cljs +++ b/frontend/src/app/main/data/workspace/drawing/box.cljs @@ -8,11 +8,13 @@ (:require [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] + [app.common.geom.shapes.flex-layout :as gsl] [app.common.math :as mth] [app.common.pages.helpers :as cph] [app.common.types.modifiers :as ctm] [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] + [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid] [app.main.data.workspace.drawing.common :as common] [app.main.data.workspace.state-helpers :as wsh] @@ -72,23 +74,30 @@ initial (cond-> @ms/mouse-position snap-pixel? gpt/round) - 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) + 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) + drop-index (when layout? (gsl/get-drop-index fid objects initial)) shape (get-in state [:workspace-drawing :object]) shape (-> shape (cts/setup-shape {:x (:x initial) - :y (:y initial) - :width 0.01 - :height 0.01}) + :y (:y initial) + :width 0.01 + :height 0.01}) (cond-> (and (cph/frame-shape? shape) (not= fid uuid/zero)) (assoc :fills [] :hide-in-viewer true)) (assoc :frame-id fid) + + (cond-> (some? drop-index) + (with-meta {:index drop-index})) + (assoc :initialized? true) (assoc :click-draw? true))] (rx/concat diff --git a/frontend/src/app/main/data/workspace/drawing/curve.cljs b/frontend/src/app/main/data/workspace/drawing/curve.cljs index 2206763e15..1f3000eb93 100644 --- a/frontend/src/app/main/data/workspace/drawing/curve.cljs +++ b/frontend/src/app/main/data/workspace/drawing/curve.cljs @@ -6,9 +6,12 @@ (ns app.main.data.workspace.drawing.curve (:require + [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] + [app.common.geom.shapes.flex-layout :as gsl] [app.common.geom.shapes.path :as gsp] [app.common.types.shape-tree :as ctst] + [app.common.types.shape.layout :as ctl] [app.main.data.workspace.drawing.common :as common] [app.main.data.workspace.state-helpers :as wsh] [app.main.streams :as ms] @@ -46,10 +49,14 @@ (let [objects (wsh/lookup-page-objects state) content (get-in state [:workspace-drawing :object :content] []) - position (get-in content [0 :params] nil) - frame-id (ctst/top-nested-frame objects position)] + position (gpt/point (get-in content [0 :params] nil)) + frame-id (ctst/top-nested-frame objects position) + layout? (ctl/layout? objects frame-id) + drop-index (when layout? (gsl/get-drop-index frame-id objects position))] (-> state - (assoc-in [:workspace-drawing :object :frame-id] frame-id)))))) + (assoc-in [:workspace-drawing :object :frame-id] frame-id) + (cond-> (some? drop-index) + (update-in [:workspace-drawing :object] with-meta {:index drop-index}))))))) (defn curve-to-path [{:keys [segments] :as shape}] (let [content (gsp/segments->content segments) diff --git a/frontend/src/app/main/data/workspace/groups.cljs b/frontend/src/app/main/data/workspace/groups.cljs index 509589ba76..77cf227a70 100644 --- a/frontend/src/app/main/data/workspace/groups.cljs +++ b/frontend/src/app/main/data/workspace/groups.cljs @@ -24,9 +24,8 @@ [objects selected] (->> selected (cph/order-by-indexed-shapes objects) - (map #(get objects %)) - (map #(assoc % ::index (cph/get-position-on-parent objects (:id %)))) - (sort-by ::index))) + reverse + (map #(get objects %)))) (defn- get-empty-groups-after-group-creation "An auxiliary function that finds and returns a set of ids that @@ -78,7 +77,11 @@ (ctst/generate-unique-name base-name))) selrect (gsh/selection-rect shapes) - group-idx (inc (::index (last shapes))) + group-idx (->> shapes + last + :id + (cph/get-position-on-parent objects) + inc) group (-> (cts/make-minimal-group frame-id selrect gname) (cts/setup-shape selrect) (assoc :shapes (mapv :id shapes) @@ -115,7 +118,8 @@ (->> (:shapes parent) (map-indexed vector) (filter #(#{(:id group)} (second %))) - (ffirst)) + (ffirst) + inc) ;; Shapes that are in a component (including root) must be detached, ;; because cannot be easyly synchronized back to the main component. @@ -134,7 +138,9 @@ (cph/order-by-indexed-shapes objects) (mapv #(get objects %))) parent-id (cph/get-parent-id objects (:id frame)) - idx-in-parent (cph/get-position-on-parent objects (:id frame))] + idx-in-parent (->> (:id frame) + (cph/get-position-on-parent objects) + inc)] (-> (pcb/empty-changes it page-id) (pcb/with-objects objects) diff --git a/frontend/src/app/main/data/workspace/path/drawing.cljs b/frontend/src/app/main/data/workspace/path/drawing.cljs index ad0f5e2345..fddb6c9142 100644 --- a/frontend/src/app/main/data/workspace/path/drawing.cljs +++ b/frontend/src/app/main/data/workspace/path/drawing.cljs @@ -7,11 +7,13 @@ (ns app.main.data.workspace.path.drawing (: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] [app.common.types.shape-tree :as ctst] + [app.common.types.shape.layout :as ctl] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.drawing.common :as dwdc] [app.main.data.workspace.edition :as dwe] @@ -257,10 +259,14 @@ (update [_ state] (let [objects (wsh/lookup-page-objects state) content (get-in state [:workspace-drawing :object :content] []) - position (get-in content [0 :params] nil) - frame-id (ctst/top-nested-frame objects position)] + position (gpt/point (get-in content [0 :params] nil)) + frame-id (ctst/top-nested-frame objects position) + layout? (ctl/layout? objects frame-id) + drop-index (when layout? (gsl/get-drop-index frame-id objects position))] (-> state - (assoc-in [:workspace-drawing :object :frame-id] frame-id)))))) + (assoc-in [:workspace-drawing :object :frame-id] frame-id) + (cond-> (some? drop-index) + (update-in [:workspace-drawing :object] with-meta {:index drop-index}))))))) (defn handle-new-shape-result [shape-id] (ptk/reify ::handle-new-shape-result diff --git a/frontend/src/app/main/data/workspace/path/edition.cljs b/frontend/src/app/main/data/workspace/path/edition.cljs index a112da6575..b8712111b0 100644 --- a/frontend/src/app/main/data/workspace/path/edition.cljs +++ b/frontend/src/app/main/data/workspace/path/edition.cljs @@ -298,7 +298,10 @@ ptk/WatchEvent (watch [_ state stream] (let [mode (get-in state [:workspace-local :edit-path id :edit-mode]) - stopper (->> stream (rx/filter (ptk/type? ::start-path-edit))) + stopper (->> stream + (rx/filter #(or + (= (ptk/type %) ::dwe/clear-edition-mode) + (= (ptk/type %) ::start-path-edit)))) interrupt (->> stream (rx/filter #(= % :interrupt)) (rx/take 1))] (rx/concat (rx/of (undo/start-path-undo)) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 8ca06bd2d5..e7a3427f3e 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -82,11 +82,13 @@ [ids] (ptk/reify ::update-layout-positions ptk/WatchEvent - (watch [_ _ _] - (if (d/not-empty? ids) - (let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))] - (rx/of (dwm/apply-modifiers {:modifiers modif-tree}))) - (rx/empty))))) + (watch [_ state _] + (let [objects (wsh/lookup-page-objects state) + ids (->> ids (filter #(contains? objects %)))] + (if (d/not-empty? ids) + (let [modif-tree (dwm/create-modif-tree ids (ctm/reflow-modifiers))] + (rx/of (dwm/apply-modifiers {:modifiers modif-tree}))) + (rx/empty)))))) (defn initialize [] diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index 94ab70ebdd..4bba01db83 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -96,11 +96,12 @@ objects selected) + index (:index (meta attrs)) changes (-> (pcb/empty-changes it page-id) (pcb/with-objects objects) - (cond-> (some? (:index (meta attrs))) - (pcb/add-object shape {:index (:index (meta attrs))})) - (cond-> (nil? (:index (meta attrs))) + (cond-> (some? index) + (pcb/add-object shape {:index index})) + (cond-> (nil? index) (pcb/add-object shape)) (cond-> (some? (:parent-id attrs)) (pcb/change-parent (:parent-id attrs) [shape]))) diff --git a/frontend/src/app/main/store.cljs b/frontend/src/app/main/store.cljs index 0c66507fc4..cb2d99824b 100644 --- a/frontend/src/app/main/store.cljs +++ b/frontend/src/app/main/store.cljs @@ -23,22 +23,29 @@ [type data] (ptk/data-event type data)) -;;(def debug-exclude-events -;; #{:app.main.data.workspace.notifications/handle-pointer-update -;; :app.main.data.workspace.notifications/handle-pointer-send -;; :app.main.data.workspace.persistence/update-persistence-status -;; :app.main.data.workspace.changes/update-indices -;; :app.main.data.websocket/send-message -;; :app.main.data.workspace.selection/change-hover-state}) -;; (def ^:dynamic *debug-events* false) +(def on-event identity) + +(def ^:dynamic *debug-events* false) + +;; Only created in development build +(when *assert* + (def debug-exclude-events + #{:app.main.data.workspace.notifications/handle-pointer-update + :app.main.data.workspace.notifications/handle-pointer-send + :app.main.data.workspace.persistence/update-persistence-status + :app.main.data.workspace.changes/update-indices + :app.main.data.websocket/send-message + :app.main.data.workspace.selection/change-hover-state}) + + (set! on-event (fn [e] + (when (and *debug-events* + (ptk/event? e) + (not (debug-exclude-events (ptk/type e)))) + (.log js/console (str "[stream]: " (ptk/repr-event e)) ))))) (defonce state (ptk/store {:resolve ptk/resolve - ;;:on-event (fn [e] - ;; (when (and *debug-events* - ;; (ptk/event? e) - ;; (not (debug-exclude-events (ptk/type e)))) - ;; (.log js/console (str "[stream]: " (ptk/repr-event e)) ))) + :on-event on-event :on-error (fn [e] (@on-error e))})) (defonce stream diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs index f73424ecd2..4254b09063 100644 --- a/frontend/src/app/main/ui/icons.cljs +++ b/frontend/src/app/main/ui/icons.cljs @@ -78,6 +78,7 @@ (def bool-intersection (icon-xref :boolean-intersection)) (def bool-union (icon-xref :boolean-union)) (def box (icon-xref :box)) +(def bug (icon-xref :bug)) (def chain (icon-xref :chain)) (def chat (icon-xref :chat)) (def checkbox-checked (icon-xref :checkbox-checked)) diff --git a/frontend/src/app/main/ui/shapes/attrs.cljs b/frontend/src/app/main/ui/shapes/attrs.cljs index 7047cb793e..7b9275ba73 100644 --- a/frontend/src/app/main/ui/shapes/attrs.cljs +++ b/frontend/src/app/main/ui/shapes/attrs.cljs @@ -146,18 +146,20 @@ (defn extract-svg-attrs [render-id svg-defs svg-attrs] - (let [replace-id (fn [id] - (if (contains? svg-defs id) - (str render-id "-" id) - id)) - svg-attrs (-> svg-attrs - (usvg/clean-attrs) - (usvg/update-attr-ids replace-id) - (dissoc :id)) + (if (and (empty? svg-defs) (empty? svg-attrs)) + [nil nil] + (let [replace-id (fn [id] + (if (contains? svg-defs id) + (str render-id "-" id) + id)) + svg-attrs (-> svg-attrs + (usvg/clean-attrs) + (usvg/update-attr-ids replace-id) + (dissoc :id)) - attrs (-> svg-attrs (dissoc :style) (clj->js)) - styles (-> svg-attrs (:style {}) (clj->js))] - [attrs styles])) + attrs (-> svg-attrs (dissoc :style) (clj->js)) + styles (-> svg-attrs (:style {}) (clj->js))] + [attrs styles]))) (defn add-style-attrs ([props shape] @@ -212,9 +214,12 @@ (obj/set! "style" styles))))) (defn extract-style-attrs - [shape] - (-> (obj/create) - (add-style-attrs shape))) + ([shape] + (-> (obj/create) + (add-style-attrs shape))) + ([shape render-id] + (-> (obj/create) + (add-style-attrs shape render-id)))) (defn extract-fill-attrs [fill-data render-id index type] diff --git a/frontend/src/app/main/ui/shapes/frame.cljs b/frontend/src/app/main/ui/shapes/frame.cljs index 702f956b78..05c9c3ec7b 100644 --- a/frontend/src/app/main/ui/shapes/frame.cljs +++ b/frontend/src/app/main/ui/shapes/frame.cljs @@ -53,7 +53,10 @@ {:keys [x y width height show-content]} shape transform (gsh/transform-str shape) - props (-> (attrs/extract-style-attrs shape) + + render-id (mf/use-ctx muc/render-id) + + props (-> (attrs/extract-style-attrs shape render-id) (obj/merge! #js {:x x :y y @@ -61,9 +64,7 @@ :width width :height height :className "frame-background"})) - path? (some? (.-d props)) - render-id (mf/use-ctx muc/render-id)] - + path? (some? (.-d props))] [:* [:g {:clip-path (when (not show-content) (frame-clip-url shape render-id))} [:& frame-clip-def {:shape shape :render-id render-id}] diff --git a/frontend/src/app/main/ui/workspace/left_toolbar.cljs b/frontend/src/app/main/ui/workspace/left_toolbar.cljs index bf01aa001b..de16a19c3b 100644 --- a/frontend/src/app/main/ui/workspace/left_toolbar.cljs +++ b/frontend/src/app/main/ui/workspace/left_toolbar.cljs @@ -177,6 +177,19 @@ :on-click (fn [] (let [is-sidebar-closed? (contains? layout :collapse-left-sidebar)] (ts/schedule 300 #(st/emit! (when is-sidebar-closed? (dw/toggle-layout-flag :collapse-left-sidebar)) + (dw/remove-layout-flag :debug-panel) (-> (dw/toggle-layout-flag :shortcuts) (vary-meta assoc ::ev/origin "workspace-left-toolbar"))))))} - i/shortcut]]]])) + i/shortcut] + + (when *assert* + [:button.tooltip.tooltip-right + {:alt "Debugging tool" + :class (when (contains? layout :debug-panel) "selected") + :on-click (fn [] + (let [is-sidebar-closed? (contains? layout :collapse-left-sidebar)] + (ts/schedule 300 #(st/emit! (when is-sidebar-closed? (dw/toggle-layout-flag :collapse-left-sidebar)) + (dw/remove-layout-flag :shortcuts) + (-> (dw/toggle-layout-flag :debug-panel) + (vary-meta assoc ::ev/origin "workspace-left-toolbar"))))))} + i/bug])]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs index cf61c1e9ec..02f2c6be54 100644 --- a/frontend/src/app/main/ui/workspace/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar.cljs @@ -14,6 +14,7 @@ [app.main.ui.icons :as i] [app.main.ui.workspace.comments :refer [comments-sidebar]] [app.main.ui.workspace.sidebar.assets :refer [assets-toolbox]] + [app.main.ui.workspace.sidebar.debug :refer [debug-panel]] [app.main.ui.workspace.sidebar.history :refer [history-toolbox]] [app.main.ui.workspace.sidebar.layers :refer [layers-toolbox]] [app.main.ui.workspace.sidebar.options :refer [options-toolbox]] @@ -34,6 +35,7 @@ section (cond (or mode-inspect? (contains? layout :layers)) :layers (contains? layout :assets) :assets) shortcuts? (contains? layout :shortcuts) + show-debug? (contains? layout :debug-panel) {:keys [on-pointer-down on-lost-pointer-capture on-mouse-move parent-ref size]} (use-resize-hook :left-sidebar 255 255 500 :x false :left) @@ -53,26 +55,31 @@ :on-mouse-move on-mouse-move}] [:div.settings-bar-inside + (cond + shortcuts? + [:& shortcuts-container] - [:* (if shortcuts? - [:& shortcuts-container] - [:* - [:button.collapse-sidebar - {:on-click handle-collapse - :aria-label (tr "workspace.sidebar.collapse")} - i/arrow-slide] - [:& tab-container {:on-change-tab #(st/emit! (dw/go-to-layout %)) - :selected section - :shortcuts? shortcuts?} + show-debug? + [:& debug-panel] - [:& tab-element {:id :layers :title (tr "workspace.sidebar.layers")} - [:div.layers-tab - [:& sitemap {:layout layout}] - [:& layers-toolbox]]] + :else + [:* + [:button.collapse-sidebar + {:on-click handle-collapse + :aria-label (tr "workspace.sidebar.collapse")} + i/arrow-slide] + [:& tab-container {:on-change-tab #(st/emit! (dw/go-to-layout %)) + :selected section + :shortcuts? shortcuts?} - (when-not mode-inspect? - [:& tab-element {:id :assets :title (tr "workspace.toolbar.assets")} - [:& assets-toolbox]])]])]]])) + [:& tab-element {:id :layers :title (tr "workspace.sidebar.layers")} + [:div.layers-tab + [:& sitemap {:layout layout}] + [:& layers-toolbox]]] + + (when-not mode-inspect? + [:& tab-element {:id :assets :title (tr "workspace.toolbar.assets")} + [:& assets-toolbox]])]])]])) ;; --- Right Sidebar (Component) diff --git a/frontend/src/app/main/ui/workspace/sidebar/debug.cljs b/frontend/src/app/main/ui/workspace/sidebar/debug.cljs new file mode 100644 index 0000000000..82c099f847 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/debug.cljs @@ -0,0 +1,51 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + +(ns app.main.ui.workspace.sidebar.debug + (:require + [app.common.data :as d] + [app.main.data.workspace :as dw] + [app.main.store :as st] + [app.main.ui.icons :as i] + [app.util.dom :as dom] + [debug :as dbg] + [rumext.v2 :as mf])) + +(mf/defc debug-panel + [] + (let [on-toggle-enabled + (mf/use-callback + (fn [event option] + (dom/prevent-default event) + (dom/stop-propagation event) + (if (contains? @dbg/*debug* option) + (dbg/-debug! option) + (dbg/debug! option)))) + + close-fn + (mf/use-callback + (fn [] + (st/emit! (dw/remove-layout-flag :debug-panel))))] + [:div.debug-panel + [:div.debug-panel-header + [:div.debug-panel-close-button + {:on-click close-fn} i/close] + [:div.debug-panel-title "Debugging tools"]] + + [:div.debug-panel-inner + [:* + (for [option (sort-by d/name dbg/debug-options)] + [:div.debug-option {:key (d/name option) + :on-click #(on-toggle-enabled % option)} + [:input {:type "checkbox" + :id (d/name option) + :on-change #(on-toggle-enabled % option) + :checked (contains? @dbg/*debug* option)}] + [:div.field.check + (if (contains? @dbg/*debug* option) + [:span.checked i/checkbox-checked] + [:span.unchecked i/checkbox-unchecked])] + [:label {:for (d/name option)} (d/name option)]])]]])) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 538d27c7ef..b0aba960e1 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -214,7 +214,7 @@ (hooks/setup-viewport-size viewport-ref) (hooks/setup-cursor cursor alt? mod? space? panning drawing-tool drawing-path? node-editing? workspace-read-only?) (hooks/setup-keyboard alt? mod? space?) - (hooks/setup-hover-shapes page-id move-stream base-objects transform selected mod? hover hover-ids hover-top-frame-id @hover-disabled? focus zoom) + (hooks/setup-hover-shapes page-id move-stream base-objects transform selected mod? hover hover-ids hover-top-frame-id @hover-disabled? focus zoom show-measures?) (hooks/setup-viewport-modifiers modifiers base-objects) (hooks/setup-shortcuts node-editing? drawing-path?) (hooks/setup-active-frames base-objects hover-ids selected active-frames zoom transform vbox) diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs index 5076cb86fd..6df2d16c96 100644 --- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs @@ -117,7 +117,7 @@ (not)))) (defn setup-hover-shapes - [page-id move-stream objects transform selected mod? hover hover-ids hover-top-frame-id hover-disabled? focus zoom] + [page-id move-stream objects transform selected mod? hover hover-ids hover-top-frame-id hover-disabled? focus zoom show-measures?] (let [;; We use ref so we don't recreate the stream on a change zoom-ref (mf/use-ref zoom) mod-ref (mf/use-ref @mod?) @@ -192,7 +192,7 @@ (hooks/use-stream over-shapes-stream - (mf/deps page-id objects) + (mf/deps page-id objects show-measures?) (fn [ids] (let [selected (mf/ref-val selected-ref) focus (mf/ref-val focus-ref) @@ -212,15 +212,20 @@ (and (cph/root-frame? obj) (d/not-empty? (:shapes obj)))) ;; Set with the elements to remove from the hover list - remove-id? - (cond-> selected-with-parents - (not mod?) - (into (filter #(or (root-frame-with-data? %) - (group-empty-space? % objects ids))) - ids) - + remove-id-xf + (cond mod? - (into (filter grouped?) ids)) + (filter grouped?) + + show-measures? + (filter #(group-empty-space? % objects ids)) + + (not mod?) + (filter #(or (root-frame-with-data? %) + (group-empty-space? % objects ids)))) + + remove-id? + (into selected-with-parents remove-id-xf ids) hover-shape (->> ids diff --git a/frontend/src/app/util/path/format.cljs b/frontend/src/app/util/path/format.cljs index 25a198acc7..e9c36d50d5 100644 --- a/frontend/src/app/util/path/format.cljs +++ b/frontend/src/app/util/path/format.cljs @@ -6,7 +6,6 @@ (ns app.util.path.format (:require - [app.common.math :as mth] [app.common.path.commands :as upc] [app.common.path.subpaths :refer [pt=]] [app.util.array :as arr])) @@ -16,48 +15,48 @@ (defn- join-params ([a] (js* "\"\"+~{}" - (mth/precision a path-precision))) + (.toFixed a path-precision))) ([a b] (js* "\"\"+~{}+\",\"+~{}" - (mth/precision a path-precision) - (mth/precision b path-precision))) + (.toFixed a path-precision) + (.toFixed b path-precision))) ([a b c] (js* "\"\"+~{}+\",\"+~{}+\",\"+~{}" - (mth/precision a path-precision) - (mth/precision b path-precision) - (mth/precision c path-precision))) + (.toFixed a path-precision) + (.toFixed b path-precision) + (.toFixed c path-precision))) ([a b c d] (js* "\"\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}" - (mth/precision a path-precision) - (mth/precision b path-precision) - (mth/precision c path-precision) - (mth/precision d path-precision) + (.toFixed a path-precision) + (.toFixed b path-precision) + (.toFixed c path-precision) + (.toFixed d path-precision) )) ([a b c d e] (js* "\"\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}" - (mth/precision a path-precision) - (mth/precision b path-precision) - (mth/precision c path-precision) - (mth/precision d path-precision) - (mth/precision e path-precision))) + (.toFixed a path-precision) + (.toFixed b path-precision) + (.toFixed c path-precision) + (.toFixed d path-precision) + (.toFixed e path-precision))) ([a b c d e f] (js* "\"\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}" - (mth/precision a path-precision) - (mth/precision b path-precision) - (mth/precision c path-precision) - (mth/precision d path-precision) - (mth/precision e path-precision) - (mth/precision f path-precision) + (.toFixed a path-precision) + (.toFixed b path-precision) + (.toFixed c path-precision) + (.toFixed d path-precision) + (.toFixed e path-precision) + (.toFixed f path-precision) )) ([a b c d e f g] (js* "\"\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}+\",\"+~{}" - (mth/precision a path-precision) - (mth/precision b path-precision) - (mth/precision c path-precision) - (mth/precision d path-precision) - (mth/precision e path-precision) - (mth/precision f path-precision) - (mth/precision g path-precision)))) + (.toFixed a path-precision) + (.toFixed b path-precision) + (.toFixed c path-precision) + (.toFixed d path-precision) + (.toFixed e path-precision) + (.toFixed f path-precision) + (.toFixed g path-precision)))) (defn- translate-params [command {:keys [x y] :as params}] diff --git a/frontend/src/app/util/strings.cljs b/frontend/src/app/util/strings.cljs index edbe863544..0eb5f74c85 100644 --- a/frontend/src/app/util/strings.cljs +++ b/frontend/src/app/util/strings.cljs @@ -42,3 +42,8 @@ (let [st (str/trim (str/lower search-term)) nm (str/trim (str/lower name))] (str/includes? nm st)))) + +(defn camelize + [str] + ;; str.replace(":", "-").replace(/-./g, x=>x[1].toUpperCase()) + (js* "~{}.replace(\":\", \"-\").replace(/-./g, x=>x[1].toUpperCase())", str)) diff --git a/frontend/src/app/util/svg.cljs b/frontend/src/app/util/svg.cljs index 8a44d64506..03d541fa5c 100644 --- a/frontend/src/app/util/svg.cljs +++ b/frontend/src/app/util/svg.cljs @@ -12,6 +12,7 @@ [app.common.geom.shapes :as gsh] [app.common.math :as mth] [app.common.uuid :as uuid] + [app.util.strings :as ustr] [cuerdas.core :as str])) ;; Regex for XML ids per Spec @@ -566,19 +567,20 @@ (defn clean-attrs "Transforms attributes to their react equivalent" - ([attrs] (clean-attrs attrs true)) + ([attrs] + (clean-attrs attrs true)) + ([attrs whitelist?] (letfn [(known-property? [[key _]] (or (not whitelist?) - (contains? svg-attr-list key ) - (contains? svg-present-list key ))) + (contains? svg-attr-list key) + (contains? svg-present-list key))) - (transform-key [key] + (transform-att [key] (if (contains? non-react-props key) key (-> (d/name key) - (str/replace ":" "-") - (str/camel) + (ustr/camelize) (keyword)))) (format-styles [style-str] @@ -588,25 +590,27 @@ (group-by first) (map (fn [[key val]] (vector - (transform-key key) + (transform-att key) (second (first val))))) (into {}))) - (map-fn [[key val]] - (let [key (keyword key)] + (clean-att [[att val]] + (let [att (keyword att)] (cond - (= key :class) [:className val] - (and (= key :style) (string? val)) [key (format-styles val)] - (and (= key :style) (map? val)) [key (clean-attrs val false)] - :else (vector (transform-key key) val)))) + (= att :class) [:className val] + (and (= att :style) (string? val)) [att (format-styles val)] + (and (= att :style) (map? val)) [att (clean-attrs val false)] + :else [(transform-att att) val])))] - ] + ;; Removed this warning because slows a lot rendering with big svgs + #_(let [filtered-props (->> attrs (remove known-property?) (map first))] + (when (seq filtered-props) + (.warn js/console "Unknown properties: " (str/join ", " filtered-props )))) - (let [filtered-props (->> attrs (remove known-property?) (map first))] - (when (seq filtered-props) - (.warn js/console "Unknown properties: " (str/join ", " filtered-props )))) - - (into {} (comp (filter known-property?) (map map-fn)) attrs)))) + (into {} + (comp (filter known-property?) + (map clean-att)) + attrs)))) (defn update-attr-ids "Replaces the ids inside a property" diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index f2d2e729ab..e78a24dc8d 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -86,6 +86,9 @@ ;; Show html text :html-text + + ;; Show history overlay + :history-overlay }) ;; These events are excluded when we activate the :events flag @@ -99,10 +102,26 @@ (defonce ^:dynamic *debug* (atom #{#_:events})) -(defn debug-all! [] (reset! *debug* debug-options)) -(defn debug-none! [] (reset! *debug* #{})) -(defn debug! [option] (swap! *debug* conj option)) -(defn -debug! [option] (swap! *debug* disj option)) +(defn debug-all! [] + (reset! *debug* debug-options) + (js* "app.main.reinit()")) + +(defn debug-none! [] + (reset! *debug* #{}) + (js* "app.main.reinit()")) + +(defn debug! [option] + (swap! *debug* conj option) + (when (= :events option) + (set! st/*debug-events* true)) + + (js* "app.main.reinit()")) + +(defn -debug! [option] + (swap! *debug* disj option) + (when (= :events option) + (set! st/*debug-events* false)) + (js* "app.main.reinit()")) (defn ^:export ^boolean debug? [option]