diff --git a/CHANGES.md b/CHANGES.md index a40fdae18..54b0704db 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ ### :sparkles: New features ### :bug: Bugs fixed +- Add title to color bullets [Taiga #4218](https://tree.taiga.io/project/penpot/task/4218) - Fix color bullets in library color modal [Taiga #4186](https://tree.taiga.io/project/penpot/issue/4186) - Fix shortcut texts alignment [Taiga #4275](https://tree.taiga.io/project/penpot/issue/4275) - Fix some texts and a typo [Taiga #4215](https://tree.taiga.io/project/penpot/issue/4215) @@ -27,7 +28,7 @@ ### :sparkles: New features -- Add title to color bullets [Taiga #4218](https://tree.taiga.io/project/penpot/task/4218) +- Improve interactions with nested boards [Taiga #4054](https://tree.taiga.io/project/penpot/us/4054) - Add team hero in projects dashboard [Taiga #3863](https://tree.taiga.io/project/penpot/us/3863) - Add zoom style to shared link [Taiga #3874](https://tree.taiga.io/project/penpot/us/3874) - Add dashboard creation button as placeholder [Taiga #3861](https://tree.taiga.io/project/penpot/us/3861) @@ -42,6 +43,7 @@ - Newsletter Opt-in options for subscription categories [Taiga #3242](https://tree.taiga.io/project/penpot/us/3242) - Print emails to console by default if smtp is disabled - Add `email-verification` flag for enable/disable email verification +- Make graphics thumbnails load lazy [Taiga #4252](https://tree.taiga.io/project/penpot/issue/4252) ### :bug: Bugs fixed @@ -55,6 +57,7 @@ - Fix change multiple colors with SVG [Taiga #3889](https://tree.taiga.io/project/penpot/issue/3889) - Fix ungroup does not work for typographies [Taiga #4195](https://tree.taiga.io/project/penpot/issue/4195) - Fix inviting to non existing users can fail [Taiga #4108](https://tree.taiga.io/project/penpot/issue/4108) +- Fix components marked as touched when moved [Taiga #4061](https://tree.taiga.io/project/penpot/task/4061) ### :arrow_up: Deps updates ### :heart: Community contributions by (Thank you!) diff --git a/backend/deps.edn b/backend/deps.edn index e08b9e422..b18dfd124 100644 --- a/backend/deps.edn +++ b/backend/deps.edn @@ -11,17 +11,22 @@ io.prometheus/simpleclient {:mvn/version "0.16.0"} io.prometheus/simpleclient_hotspot {:mvn/version "0.16.0"} - io.prometheus/simpleclient_jetty {:mvn/version "0.16.0" - :exclusions [org.eclipse.jetty/jetty-server - org.eclipse.jetty/jetty-servlet]} + io.prometheus/simpleclient_jetty + {:mvn/version "0.16.0" + :exclusions [org.eclipse.jetty/jetty-server + org.eclipse.jetty/jetty-servlet]} + + io.prometheus/simpleclient_httpserver {:mvn/version "0.16.0"} io.lettuce/lettuce-core {:mvn/version "6.2.0.RELEASE"} java-http-clj/java-http-clj {:mvn/version "0.4.3"} - funcool/yetti {:git/tag "v9.8" :git/sha "fbe1d7d" - :git/url "https://github.com/funcool/yetti.git" - :exclusions [org.slf4j/slf4j-api]} + funcool/yetti + {:git/tag "v9.9" + :git/sha "f0a455d" + :git/url "https://github.com/funcool/yetti.git" + :exclusions [org.slf4j/slf4j-api]} com.github.seancorfield/next.jdbc {:mvn/version "1.3.828"} metosin/reitit-core {:mvn/version "0.5.18"} @@ -34,8 +39,10 @@ buddy/buddy-sign {:mvn/version "3.4.333"} org.jsoup/jsoup {:mvn/version "1.15.1"} - org.im4java/im4java {:git/tag "1.4.0-penpot-2" :git/sha "e2b3e16" - :git/url "https://github.com/penpot/im4java"} + org.im4java/im4java + {:git/tag "1.4.0-penpot-2" + :git/sha "e2b3e16" + :git/url "https://github.com/penpot/im4java"} org.lz4/lz4-java {:mvn/version "1.8.0"} diff --git a/backend/src/app/http/debug.clj b/backend/src/app/http/debug.clj index c66a14bd7..96258b1e6 100644 --- a/backend/src/app/http/debug.clj +++ b/backend/src/app/http/debug.clj @@ -280,7 +280,7 @@ (assoc ::binf/file-ids file-ids) (assoc ::binf/embed-assets? embed?) (assoc ::binf/include-libraries? libs?) - (binf/export!))] + (binf/export-to-tmpfile!))] (if clone? (let [project-id (some-> (profile/retrieve-additional-data pool profile-id) :default-project-id)] (binf/import! diff --git a/backend/src/app/http/websocket.clj b/backend/src/app/http/websocket.clj index 154319378..7e16d74f6 100644 --- a/backend/src/app/http/websocket.clj +++ b/backend/src/app/http/websocket.clj @@ -89,7 +89,7 @@ [id] (when-let [wsp (get @state id)] {:id id - :created-at (dt/instant id) + :created-at (::created-at @wsp) :profile-id (::profile-id @wsp) :session-id (::session-id @wsp) :user-agent (::ws/user-agent @wsp) diff --git a/backend/src/app/rpc/commands/binfile.clj b/backend/src/app/rpc/commands/binfile.clj index b52e02c12..013beac9f 100644 --- a/backend/src/app/rpc/commands/binfile.clj +++ b/backend/src/app/rpc/commands/binfile.clj @@ -30,7 +30,8 @@ [clojure.walk :as walk] [cuerdas.core :as str] [datoteka.io :as io] - [yetti.adapter :as yt]) + [yetti.adapter :as yt] + [yetti.response :as yrs]) (:import com.github.luben.zstd.ZstdInputStream com.github.luben.zstd.ZstdOutputStream @@ -799,27 +800,40 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn export! - [cfg] - (let [path (tmp/tempfile :prefix "penpot.export.") - id (uuid/next) - ts (dt/now) - cs (volatile! nil)] + [cfg output] + (let [id (uuid/next) + tp (dt/tpoint) + ab (volatile! false) + cs (volatile! nil)] (try (l/info :hint "start exportation" :export-id id) - (with-open [output (io/output-stream path)] + (with-open [output (io/output-stream output)] (binding [*position* (atom 0)] - (write-export! (assoc cfg ::output output)) - path)) + (write-export! (assoc cfg ::output output)))) + + (catch java.io.IOException _cause + ;; Do nothing, EOF means client closes connection abruptly + (vreset! ab true) + nil) (catch Throwable cause (vreset! cs cause) + (vreset! ab true) (throw cause)) (finally (l/info :hint "exportation finished" :export-id id - :elapsed (str (inst-ms (dt/diff ts (dt/now))) "ms") + :elapsed (str (inst-ms (tp)) "ms") + :aborted @ab :cause @cs))))) +(defn export-to-tmpfile! + [cfg] + (let [path (tmp/tempfile :prefix "penpot.export.")] + (with-open [output (io/output-stream path)] + (export! cfg output) + path))) + (defn import! [{:keys [::input] :as cfg}] (let [id (uuid/next) @@ -855,17 +869,20 @@ "Export a penpot file in a binary format." {::doc/added "1.15"} [{:keys [pool] :as cfg} {:keys [profile-id file-id include-libraries? embed-assets?] :as params}] - (db/with-atomic [conn pool] - (files/check-read-permissions! conn profile-id file-id) - (let [path (export! (assoc cfg - ::file-ids [file-id] - ::embed-assets? embed-assets? - ::include-libraries? include-libraries?))] - (with-meta {} - {:transform-response (fn [_ response] - (assoc response - :body (io/input-stream path) - :headers {"content-type" "application/octet-stream"}))})))) + (files/check-read-permissions! pool profile-id file-id) + (let [resp (reify yrs/StreamableResponseBody + (-write-body-to-stream [_ _ output-stream] + (-> cfg + (assoc ::file-ids [file-id]) + (assoc ::embed-assets? embed-assets?) + (assoc ::include-libraries? include-libraries?) + (export! output-stream))))] + + (with-meta (sv/wrap nil) + {:transform-response (fn [_ response] + (-> response + (assoc :body resp) + (assoc :headers {"content-type" "application/octet-stream"})))}))) (s/def ::file ::media/upload) (s/def ::import-binfile diff --git a/backend/src/app/util/websocket.clj b/backend/src/app/util/websocket.clj index f16b4eddc..07dc5a52a 100644 --- a/backend/src/app/util/websocket.clj +++ b/backend/src/app/util/websocket.clj @@ -10,6 +10,7 @@ [app.common.exceptions :as ex] [app.common.logging :as l] [app.common.transit :as t] + [app.common.uuid :as uuid] [app.loggers.audit :refer [parse-client-ip]] [app.util.time :as dt] [clojure.core.async :as a] @@ -21,9 +22,7 @@ (declare decode-beat) (declare encode-beat) -(declare process-heartbeat) -(declare process-input) -(declare process-output) +(declare start-io-loop) (declare ws-ping!) (declare ws-send!) (declare filter-options) @@ -51,7 +50,7 @@ ::idle-timeout] :or {input-buff-size 64 output-buff-size 64 - idle-timeout 30000 + idle-timeout 60000 on-connect noop on-snd-message identity-3 on-rcv-message identity-3} @@ -64,17 +63,19 @@ (fn [{:keys [::yws/channel session-id] :as request}] (let [input-ch (a/chan input-buff-size) output-ch (a/chan output-buff-size) - pong-ch (a/chan (a/sliding-buffer 6)) + hbeat-ch (a/chan (a/sliding-buffer 6)) close-ch (a/chan) stop-ch (a/chan) ip-addr (parse-client-ip request) uagent (yr/get-header request "user-agent") - id (inst-ms (dt/now)) + id (uuid/next) options (-> (filter-options options) (merge {::id id + ::created-at (dt/now) ::input-ch input-ch + ::heartbeat-ch hbeat-ch ::output-ch output-ch ::close-ch close-ch ::stop-ch stop-ch @@ -99,11 +100,13 @@ on-ws-error (fn [_ error] - (a/close! close-ch) (when-not (or (instance? java.nio.channels.ClosedChannelException error) (instance? java.net.SocketException error) (instance? java.io.IOException error)) - (l/error :hint (ex-message error) :cause error))) + (l/error :fn "on-ws-error" :conn-id id + :hint (ex-message error) + :cause error)) + (on-ws-terminate nil 8801 "close after error")) on-ws-message (fn [_ message] @@ -116,23 +119,18 @@ (l/warn :hint "error on decoding incoming message from websocket" :wsmsg (pr-str message) :cause e) - (a/>! close-ch [8801 "decode error"]) + (a/>! close-ch [8802 "decode error"]) (a/close! close-ch)))) on-ws-pong (fn [_ buffers] - (a/>!! pong-ch (yu/copy-many buffers)))] - - ;; Launch heartbeat process - (-> @options - (assoc ::pong-ch pong-ch) - (process-heartbeat)) + (a/>!! hbeat-ch (yu/copy-many buffers)))] ;; Wait a close signal (a/go (let [[code reason] (a/= (count issued) max-missed-heartbeats) + (on-ws-terminate nil 8802 "heartbeat: timeout") + (recur (inc i))))) + + (= p hbeat-pong-ch) + (let [beat (decode-beat v)] + (l/trace :hint "pong" :beat beat :conn-id conn-id) + (swap! beats disj beat) + (recur i)) + + (= p input-ch) + (let [result (a/! output-ch {:type :error :error (ex-data val)}) + (ex/ex-info? result) + (a/>! output-ch {:type :error :error (ex-data result)}) - (ex/exception? val) - (a/>! output-ch {:type :error :error {:message (ex-message val)}}) + (ex/exception? result) + (a/>! output-ch {:type :error :error {:message (ex-message result)}}) + + (map? result) + (a/>! output-ch (cond-> result (:request-id v) (assoc :request-id (:request-id v))))) + (recur i)) + + (= p output-ch) + (let [v (on-snd-message wsp v)] + ;; (l/trace :hint "writing message to output" :message v) + (a/! output-ch (cond-> val (:request-id message) (assoc :request-id (:request-id message))))) - (recur)))))) (a/= (count issued) max-missed-heartbeats) - (do - (a/>! close-ch [8802 "heart-beat timeout"]) - (a/close! close-ch)) - (recur (inc i))))))) - - (a/go-loop [] - (when-let [buffer (a/ (d/removev f interactions) + not-empty)) + (defn actionable? "Check if there is any interaction that is clickable by the user" [interactions] diff --git a/docker/devenv/Dockerfile b/docker/devenv/Dockerfile index c40615d8b..129d26e2c 100644 --- a/docker/devenv/Dockerfile +++ b/docker/devenv/Dockerfile @@ -142,7 +142,6 @@ RUN set -ex; \ apt-get -qqy install postgresql-client-14; \ rm -rf /var/lib/apt/lists/*; - RUN set -eux; \ ARCH="$(dpkg --print-architecture)"; \ case "${ARCH}" in \ diff --git a/frontend/src/app/main/data/workspace/interactions.cljs b/frontend/src/app/main/data/workspace/interactions.cljs index 49a199a66..c26d6ee96 100644 --- a/frontend/src/app/main/data/workspace/interactions.cljs +++ b/frontend/src/app/main/data/workspace/interactions.cljs @@ -17,6 +17,7 @@ [app.common.uuid :as uuid] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.workspace.undo :as dwu] [app.main.streams :as ms] [beicon.core :as rx] [potok.core :as ptk])) @@ -149,6 +150,29 @@ (update shape :interactions ctsi/update-interaction index update-fn))))))) +(defn remove-all-interactions-nav-to + "Remove all interactions that navigate to the given frame." + [frame-id] + (ptk/reify ::remove-all-interactions-nav-to + ptk/WatchEvent + (watch [_ state _] + (let [page-id (:current-page-id state) + objects (wsh/lookup-page-objects state page-id) + + remove-interactions-shape + (fn [shape] + (let [interactions (:interactions shape) + new-interactions (ctsi/remove-interactions #(ctsi/navs-to? % frame-id) + interactions)] + (when (not= (count interactions) (count new-interactions)) + (dch/update-shapes [(:id shape)] + (fn [shape] + (assoc shape :interactions new-interactions))))))] + + (rx/from (->> (vals objects) + (map remove-interactions-shape) + (d/vec-without-nils))))))) + (declare move-edit-interaction) (declare finish-edit-interaction) @@ -171,8 +195,7 @@ (rx/map #(move-edit-interaction initial-pos %))) (rx/of (finish-edit-interaction index initial-pos)))))))) - -(defn get-target-frame +(defn- get-target-frame [state position] (let [objects (wsh/lookup-page-objects state) @@ -185,8 +208,7 @@ target-frame (ctst/frame-by-position objects position)] (when (and (not= (:id target-frame) uuid/zero) - (not= (:id target-frame) from-frame-id) - (not (:hide-in-viewer target-frame))) + (not= (:id target-frame) from-frame-id)) target-frame))) (defn move-edit-interaction @@ -225,25 +247,34 @@ :always (ctsi/set-destination (:id target-frame))))] - (cond - (or (nil? shape) + (rx/of + (dwu/start-undo-transaction) - ;; Didn't changed the position for the interaction - (= position initial-pos) + (when (:hide-in-viewer target-frame) + ; If the target frame is hidden, we need to unhide it so + ; users can navigate to it. + (dch/update-shapes [(:id target-frame)] + #(dissoc % :hide-in-viewer))) - ;; New interaction but invalid target - (and (nil? index) (nil? target-frame))) - nil + (cond + (or (nil? shape) + ;; Didn't changed the position for the interaction + (= position initial-pos) + ;; New interaction but invalid target + (and (nil? index) (nil? target-frame))) + nil - ;; Dropped interaction in an invalid target. We remove it - (and (some? index) (nil? target-frame)) - (rx/of (remove-interaction shape index)) + ;; Dropped interaction in an invalid target. We remove it + (and (some? index) (nil? target-frame)) + (remove-interaction shape index) - (nil? index) - (rx/of (add-new-interaction shape (:id target-frame))) + (nil? index) + (add-new-interaction shape (:id target-frame)) - :else - (rx/of (update-interaction shape index change-interaction))))))) + :else + (update-interaction shape index change-interaction)) + + (dwu/commit-undo-transaction)))))) ;; --- Overlays diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 5b3d29ea5..f135affae 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -17,7 +17,6 @@ [app.common.pages.helpers :as cph] [app.common.spec :as us] [app.common.types.shape-tree :as ctst] - [app.common.uuid :as uuid] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.collapse :as dwc] [app.main.data.workspace.comments :as-alias dwcm] @@ -243,7 +242,7 @@ (defn- check-delta "If the shape is a component instance, check its relative position respect the root of the component, and see if it changes after applying a transformation." - [shape root transformed-shape transformed-root objects] + [shape root transformed-shape transformed-root objects modif-tree] (let [root (cond (:component-root? shape) @@ -260,7 +259,8 @@ transformed-shape (nil? transformed-root) - (cph/get-root-shape objects transformed-shape) + (as-> (cph/get-root-shape objects transformed-shape) $ + (gsh/transform-shape (merge $ (get modif-tree (:id $))))) :else transformed-root) @@ -298,7 +298,7 @@ transformed-shape (gsh/transform-shape (merge shape (get modif-tree shape-id))) [root transformed-root ignore-geometry?] - (check-delta shape root transformed-shape transformed-root objects) + (check-delta shape root transformed-shape transformed-root objects modif-tree) ignore-tree (assoc ignore-tree shape-id ignore-geometry?) @@ -758,9 +758,6 @@ (keep lookup) (remove #(= (:frame-id %) frame-id))) - moving-frames - (filter #(cph/frame-shape? (lookup %)) ids) - changes (-> (pcb/empty-changes it page-id) (pcb/with-objects objects) diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs index 28536cf5e..3621380be 100644 --- a/frontend/src/app/main/ui/dashboard/grid.cljs +++ b/frontend/src/app/main/ui/dashboard/grid.cljs @@ -355,8 +355,7 @@ (dnd/has-type? e "application/x-moz-file")) (dom/prevent-default e) (reset! dragging? false) - (import-files (.-files (.-dataTransfer e)))))) - ] + (import-files (.-files (.-dataTransfer e))))))] [:section.dashboard-grid {:on-drag-enter on-drag-enter diff --git a/frontend/src/app/main/ui/dashboard/libraries.cljs b/frontend/src/app/main/ui/dashboard/libraries.cljs index 4ccb6054b..a2590d53e 100644 --- a/frontend/src/app/main/ui/dashboard/libraries.cljs +++ b/frontend/src/app/main/ui/dashboard/libraries.cljs @@ -9,6 +9,7 @@ [app.common.data :as d] [app.common.math :as mth] [app.main.data.dashboard :as dd] + [app.main.features :as features] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.dashboard.grid :refer [grid]] @@ -20,20 +21,25 @@ (mf/defc libraries-page [{:keys [team] :as props}] - (let [files-map (mf/deref refs/dashboard-shared-files) - projects (mf/deref refs/dashboard-projects) + (let [files-map (mf/deref refs/dashboard-shared-files) + projects (mf/deref refs/dashboard-projects) default-project (->> projects vals (d/seek :is-default)) - files (->> (vals files-map) - (sort-by :modified-at) - (reverse)) + files (->> (vals files-map) + (sort-by :modified-at) + (reverse) + (not-empty)) - width (mf/use-state nil) - rowref (mf/use-ref) - itemsize 330 - ratio (if (some? @width) (/ @width itemsize) 0) - nitems (mth/floor ratio) - limit (min 10 nitems) - limit (max 1 limit)] + components-v2 (features/use-feature :components-v2) + + width (mf/use-state nil) + rowref (mf/use-ref) + itemsize (if (>= @width 1030) + 280 + 230) + ratio (if (some? @width) (/ @width itemsize) 0) + nitems (mth/floor ratio) + limit (min 10 nitems) + limit (max 1 limit)] (mf/use-effect (mf/deps team) (fn [] @@ -46,7 +52,7 @@ (mf/use-effect #(st/emit! (dd/fetch-shared-files) (dd/clear-selected-files))) - + (mf/with-effect (let [node (mf/ref-val rowref) mnt? (volatile! true) @@ -71,5 +77,5 @@ :project default-project :origin :libraries :limit limit - :library-view? true}]]])) + :library-view? components-v2}]]])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs index c0f1f9b5b..f1b909d7f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs @@ -12,7 +12,7 @@ [app.common.pages.helpers :as cph] [app.common.spec :as us] [app.common.text :as txt] - [app.config :as cfg] + [app.config :as cf] [app.main.data.events :as ev] [app.main.data.modal :as modal] [app.main.data.workspace :as dw] @@ -31,6 +31,7 @@ [app.main.ui.components.file-uploader :refer [file-uploader]] [app.main.ui.components.forms :as fm] [app.main.ui.context :as ctx] + [app.main.ui.hooks :as h] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.menus.typography :refer [typography-entry]] [app.util.color :as uc] @@ -135,7 +136,7 @@ on-close #(modal/hide!) on-accept - (mf/use-callback + (mf/use-fn (mf/deps form) (fn [_] (let [asset-name (get-in @form [:clean-data :asset-name])] @@ -247,8 +248,6 @@ (when (> num-selected 1) (set-drag-image event item-ref num-selected)))) - - (defn- on-drag-enter-asset-group [event dragging? prefix selected-assets-paths] (dom/stop-propagation event) @@ -270,9 +269,10 @@ ;; ---- Common blocks ---- -(def auto-pos-menu-state {:open? false - :top nil - :left nil}) +(def auto-pos-menu-state + {:open? false + :top nil + :left nil}) (defn- open-auto-pos-menu [state event] @@ -326,7 +326,7 @@ menu-state (mf/use-state auto-pos-menu-state) on-fold-group - (mf/use-callback + (mf/use-fn (mf/deps file-id box path group-open?) (fn [event] (dom/stop-propagation event) @@ -335,12 +335,12 @@ path (not group-open?))))) on-context-menu - (mf/use-callback + (mf/use-fn (fn [event] (swap! menu-state #(open-auto-pos-menu % event)))) on-close-menu - (mf/use-callback + (mf/use-fn (fn [] (swap! menu-state close-auto-pos-menu)))] @@ -371,12 +371,12 @@ dragging? (mf/use-state false) unselect-all - (mf/use-callback + (mf/use-fn (fn [] (st/emit! (dw/unselect-all-assets)))) on-component-click - (mf/use-callback + (mf/use-fn (mf/deps component selected-components) (fn [event] (dom/stop-propagation event) @@ -389,29 +389,29 @@ (on-asset-click event (:id component) unselect-all))))) on-drop - (mf/use-callback + (mf/use-fn (mf/deps component dragging? selected-components selected-components-full selected-components-paths) (fn [event] (on-drop-asset event component dragging? selected-components selected-components-full selected-components-paths dwl/rename-component))) on-drag-over - (mf/use-callback #(dom/prevent-default %)) + (mf/use-fn #(dom/prevent-default %)) on-drag-enter - (mf/use-callback + (mf/use-fn (mf/deps component dragging? selected-components selected-components-paths) (fn [event] (on-drag-enter-asset event component dragging? selected-components selected-components-paths))) on-drag-leave - (mf/use-callback + (mf/use-fn (mf/deps dragging?) (fn [event] (on-drag-leave-asset event dragging?))) on-component-drag-start - (mf/use-callback + (mf/use-fn (mf/deps component selected-components item-ref on-drag-start) (fn [event] (on-asset-drag-start event component selected-components item-ref :components on-drag-start)))] @@ -466,21 +466,21 @@ (map #(if (nil? %) "" %))) on-drag-enter - (mf/use-callback + (mf/use-fn (mf/deps dragging? prefix selected-components-paths) (fn [event] (on-drag-enter-asset-group event dragging? prefix selected-components-paths))) on-drag-leave - (mf/use-callback + (mf/use-fn (mf/deps dragging?) (fn [event] (on-drag-leave-asset event dragging?))) - on-drag-over (mf/use-callback #(dom/prevent-default %)) + on-drag-over (mf/use-fn #(dom/prevent-default %)) on-drop - (mf/use-callback + (mf/use-fn (mf/deps dragging? prefix selected-components-paths selected-components-full) (fn [event] (on-drop-asset-group event dragging? prefix selected-components-paths selected-components-full dwl/rename-component)))] @@ -567,7 +567,7 @@ groups (group-assets components reverse-sort?) on-duplicate - (mf/use-callback + (mf/use-fn (mf/deps @state) (fn [] (if (empty? selected-components) @@ -578,7 +578,7 @@ (st/emit! (dwu/commit-undo-transaction)))))) on-delete - (mf/use-callback + (mf/use-fn (mf/deps @state file-id multi-components? multi-assets?) (fn [] (if (or multi-components? multi-assets?) @@ -589,25 +589,25 @@ (dwu/commit-undo-transaction))))) on-rename - (mf/use-callback + (mf/use-fn (mf/deps @state) (fn [] (swap! state assoc :renaming (:component-id @state)))) do-rename - (mf/use-callback + (mf/use-fn (mf/deps @state) (fn [new-name] (st/emit! (dwl/rename-component (:renaming @state) new-name)) (swap! state assoc :renaming nil))) cancel-rename - (mf/use-callback + (mf/use-fn (fn [] (swap! state assoc :renaming nil))) on-context-menu - (mf/use-callback + (mf/use-fn (mf/deps selected-components on-clear-selection) (fn [component-id] (fn [event] @@ -618,12 +618,12 @@ (swap! menu-state #(open-auto-pos-menu % event)))))) on-close-menu - (mf/use-callback + (mf/use-fn (fn [] (swap! menu-state close-auto-pos-menu))) create-group - (mf/use-callback + (mf/use-fn (mf/deps components selected-components on-clear-selection) (fn [group-name] (on-clear-selection) @@ -639,7 +639,7 @@ (st/emit! (dwu/commit-undo-transaction)))) rename-group - (mf/use-callback + (mf/use-fn (mf/deps components) (fn [path last-path] (on-clear-selection) @@ -653,14 +653,14 @@ (st/emit! (dwu/commit-undo-transaction)))) on-group - (mf/use-callback + (mf/use-fn (mf/deps components selected-components) (fn [event] (dom/stop-propagation event) (modal/show! :name-group-dialog {:accept create-group}))) on-rename-group - (mf/use-callback + (mf/use-fn (mf/deps components) (fn [event path last-path] (dom/stop-propagation event) @@ -669,7 +669,7 @@ :accept rename-group}))) on-ungroup - (mf/use-callback + (mf/use-fn (mf/deps components) (fn [path] (on-clear-selection) @@ -683,7 +683,7 @@ (st/emit! (dwu/commit-undo-transaction)))) on-drag-start - (mf/use-callback + (mf/use-fn (fn [component event] (dnd/set-data! event "penpot/component" {:file-id file-id :component component}) @@ -730,36 +730,38 @@ [{:keys [object renaming listing-thumbs? selected-objects on-asset-click on-context-menu on-drag-start do-rename cancel-rename selected-graphics-full selected-graphics-paths]}] - (let [item-ref (mf/use-ref) - + (let [item-ref (mf/use-ref) + visible? (h/use-visible item-ref :once? true) dragging? (mf/use-state false) on-drop - (mf/use-callback + (mf/use-fn (mf/deps object dragging? selected-objects selected-graphics-full selected-graphics-paths) (fn [event] (on-drop-asset event object dragging? selected-objects selected-graphics-full selected-graphics-paths dwl/rename-media))) - on-drag-over (mf/use-callback #(dom/prevent-default %)) + on-drag-over (mf/use-fn #(dom/prevent-default %)) on-drag-enter - (mf/use-callback + (mf/use-fn (mf/deps object dragging? selected-objects selected-graphics-paths) (fn [event] (on-drag-enter-asset event object dragging? selected-objects selected-graphics-paths))) on-drag-leave - (mf/use-callback + (mf/use-fn (mf/deps dragging?) (fn [event] (on-drag-leave-asset event dragging?))) on-grahic-drag-start - (mf/use-callback + (mf/use-fn (mf/deps object selected-objects item-ref on-drag-start) (fn [event] - (on-asset-drag-start event object selected-objects item-ref :graphics on-drag-start)))] + (on-asset-drag-start event object selected-objects item-ref :graphics on-drag-start))) + + ] [:div {:ref item-ref :class-name (dom/classnames @@ -774,28 +776,31 @@ :on-drag-leave on-drag-leave :on-drag-over on-drag-over :on-drop on-drop} - [:img {:src (cfg/resolve-file-media object true) - :draggable false}] ;; Also need to add css pointer-events: none - (let [renaming? (= renaming (:id object))] + (when visible? [:* - [:& editable-label - {:class-name (dom/classnames - :cell-name @listing-thumbs? - :item-name (not @listing-thumbs?) - :editing renaming?) - :value (cph/merge-path-item (:path object) (:name object)) - :tooltip (cph/merge-path-item (:path object) (:name object)) - :display-value (if @listing-thumbs? - (:name object) - (cph/compact-name (:path object) - (:name object))) - :editing? renaming? - :disable-dbl-click? true - :on-change do-rename - :on-cancel cancel-rename}] - (when @dragging? - [:div.dragging])])])) + [:img {:src (when visible? (cf/resolve-file-media object true)) + :draggable false}] ;; Also need to add css pointer-events: none + + (let [renaming? (= renaming (:id object))] + [:* + [:& editable-label + {:class-name (dom/classnames + :cell-name @listing-thumbs? + :item-name (not @listing-thumbs?) + :editing renaming?) + :value (cph/merge-path-item (:path object) (:name object)) + :tooltip (cph/merge-path-item (:path object) (:name object)) + :display-value (if @listing-thumbs? + (:name object) + (cph/compact-name (:path object) + (:name object))) + :editing? renaming? + :disable-dbl-click? true + :on-change do-rename + :on-cancel cancel-rename}] + (when @dragging? + [:div.dragging])])])])) (mf/defc graphics-group [{:keys [file-id prefix groups open-groups renaming listing-thumbs? selected-objects on-asset-click @@ -811,21 +816,21 @@ on-drag-enter - (mf/use-callback + (mf/use-fn (mf/deps dragging? prefix selected-graphics-paths) (fn [event] (on-drag-enter-asset-group event dragging? prefix selected-graphics-paths))) on-drag-leave - (mf/use-callback + (mf/use-fn (mf/deps dragging?) (fn [event] (on-drag-leave-asset event dragging?))) - on-drag-over (mf/use-callback #(dom/prevent-default %)) + on-drag-over (mf/use-fn #(dom/prevent-default %)) on-drop - (mf/use-callback + (mf/use-fn (mf/deps dragging? prefix selected-graphics-paths selected-graphics-full) (fn [event] (on-drop-asset-group event dragging? prefix selected-graphics-paths selected-graphics-full dwl/rename-media)))] @@ -915,13 +920,13 @@ groups (group-assets objects reverse-sort?) add-graphic - (mf/use-callback + (mf/use-fn (fn [] #(st/emit! (dwl/set-assets-box-open file-id :graphics true)) (dom/click (mf/ref-val input-ref)))) on-file-selected - (mf/use-callback + (mf/use-fn (mf/deps file-id) (fn [blobs] (let [params {:file-id file-id @@ -931,7 +936,7 @@ :asset-type "graphics"}))))) on-delete - (mf/use-callback + (mf/use-fn (mf/deps @state multi-objects? multi-assets?) (fn [] (if (or multi-objects? multi-assets?) @@ -939,25 +944,25 @@ (st/emit! (dwl/delete-media {:id (:object-id @state)}))))) on-rename - (mf/use-callback + (mf/use-fn (mf/deps @state) (fn [] (swap! state assoc :renaming (:object-id @state)))) cancel-rename - (mf/use-callback + (mf/use-fn (fn [] (swap! state assoc :renaming nil))) do-rename - (mf/use-callback + (mf/use-fn (mf/deps @state) (fn [new-name] (st/emit! (dwl/rename-media (:renaming @state) new-name)) (swap! state assoc :renaming nil))) on-context-menu - (mf/use-callback + (mf/use-fn (mf/deps selected-objects on-clear-selection) (fn [object-id] (fn [event] @@ -968,12 +973,12 @@ (swap! menu-state #(open-auto-pos-menu % event)))))) on-close-menu - (mf/use-callback + (mf/use-fn (fn [] (swap! menu-state close-auto-pos-menu))) create-group - (mf/use-callback + (mf/use-fn (mf/deps objects selected-objects on-clear-selection) (fn [group-name] (on-clear-selection) @@ -989,7 +994,7 @@ (st/emit! (dwu/commit-undo-transaction)))) rename-group - (mf/use-callback + (mf/use-fn (mf/deps objects) (fn [path last-path] (on-clear-selection) @@ -1003,14 +1008,14 @@ (st/emit! (dwu/commit-undo-transaction)))) on-group - (mf/use-callback + (mf/use-fn (mf/deps objects selected-objects) (fn [event] (dom/stop-propagation event) (modal/show! :name-group-dialog {:accept create-group}))) on-rename-group - (mf/use-callback + (mf/use-fn (mf/deps objects) (fn [event path last-path] (dom/stop-propagation event) @@ -1018,7 +1023,7 @@ :last-path last-path :accept rename-group}))) on-ungroup - (mf/use-callback + (mf/use-fn (mf/deps objects) (fn [path] (on-clear-selection) @@ -1032,7 +1037,7 @@ (st/emit! (dwu/commit-undo-transaction)))) on-drag-start - (mf/use-callback + (mf/use-fn (fn [{:keys [name id mtype]} event] (dnd/set-data! event "text/asset-id" (str id)) (dnd/set-data! event "text/asset-name" name) @@ -1131,7 +1136,7 @@ (st/emit! (dwl/update-color updated-color file-id)))) delete-color - (mf/use-callback + (mf/use-fn (mf/deps @state multi-colors? multi-assets? file-id) (fn [] (if (or multi-colors? multi-assets?) @@ -1173,7 +1178,7 @@ :position :right})) on-context-menu - (mf/use-callback + (mf/use-fn (mf/deps color selected-colors on-clear-selection) (fn [event] (when local? @@ -1182,32 +1187,32 @@ (swap! menu-state #(open-auto-pos-menu % event))))) on-close-menu - (mf/use-callback + (mf/use-fn (fn [] (swap! menu-state close-auto-pos-menu))) on-drop - (mf/use-callback + (mf/use-fn (mf/deps color dragging? selected-colors selected-colors-full selected-colors-paths move-color) (fn [event] (on-drop-asset event color dragging? selected-colors selected-colors-full selected-colors-paths move-color))) - on-drag-over (mf/use-callback #(dom/prevent-default %)) + on-drag-over (mf/use-fn #(dom/prevent-default %)) on-drag-enter - (mf/use-callback + (mf/use-fn (mf/deps color dragging? selected-colors selected-colors-paths) (fn [event] (on-drag-enter-asset event color dragging? selected-colors selected-colors-paths))) on-drag-leave - (mf/use-callback + (mf/use-fn (mf/deps dragging?) (fn [event] (on-drag-leave-asset event dragging?))) on-color-drag-start - (mf/use-callback + (mf/use-fn (mf/deps color selected-colors item-ref) (fn [event] (on-asset-drag-start event color selected-colors item-ref :colors identity)))] @@ -1277,20 +1282,20 @@ move-color (partial dwl/rename-color file-id) on-drag-enter - (mf/use-callback + (mf/use-fn (mf/deps dragging? prefix selected-colors-paths) (fn [event] (on-drag-enter-asset-group event dragging? prefix selected-colors-paths))) - on-drag-leave (mf/use-callback + on-drag-leave (mf/use-fn (mf/deps dragging?) (fn [event] (on-drag-leave-asset event dragging?))) - on-drag-over (mf/use-callback #(dom/prevent-default %)) + on-drag-over (mf/use-fn #(dom/prevent-default %)) on-drop - (mf/use-callback + (mf/use-fn (mf/deps dragging? prefix selected-colors-paths selected-colors-full move-color) (fn [event] (on-drop-asset-group event dragging? prefix selected-colors-paths selected-colors-full move-color)))] @@ -1371,13 +1376,13 @@ groups (group-assets colors reverse-sort?) add-color - (mf/use-callback + (mf/use-fn (mf/deps file-id) (fn [value _opacity] (st/emit! (dwl/add-color value)))) add-color-clicked - (mf/use-callback + (mf/use-fn (mf/deps file-id) (fn [event] (st/emit! (dwl/set-assets-box-open file-id :colors true) @@ -1392,7 +1397,7 @@ :position :right}))) create-group - (mf/use-callback + (mf/use-fn (mf/deps colors selected-colors on-clear-selection file-id) (fn [color-id] (fn [group-name] @@ -1410,7 +1415,7 @@ (st/emit! (dwu/commit-undo-transaction))))) rename-group - (mf/use-callback + (mf/use-fn (mf/deps colors) (fn [path last-path] (on-clear-selection) @@ -1425,7 +1430,7 @@ (st/emit! (dwu/commit-undo-transaction)))) on-group - (mf/use-callback + (mf/use-fn (mf/deps colors selected-colors) (fn [color-id] (fn [event] @@ -1433,7 +1438,7 @@ (modal/show! :name-group-dialog {:accept (create-group color-id)})))) on-rename-group - (mf/use-callback + (mf/use-fn (mf/deps colors) (fn [event path last-path] (dom/stop-propagation event) @@ -1441,7 +1446,7 @@ :last-path last-path :accept rename-group}))) on-ungroup - (mf/use-callback + (mf/use-fn (mf/deps colors) (fn [path] (on-clear-selection) @@ -1492,28 +1497,28 @@ (let [item-ref (mf/use-ref) dragging? (mf/use-state false) on-drop - (mf/use-callback + (mf/use-fn (mf/deps typography dragging? selected-typographies selected-typographies-full selected-typographies-paths move-typography) (fn [event] (on-drop-asset event typography dragging? selected-typographies selected-typographies-full selected-typographies-paths move-typography))) - on-drag-over (mf/use-callback #(dom/prevent-default %)) + on-drag-over (mf/use-fn #(dom/prevent-default %)) on-drag-enter - (mf/use-callback + (mf/use-fn (mf/deps typography dragging? selected-typographies selected-typographies-paths) (fn [event] (on-drag-enter-asset event typography dragging? selected-typographies selected-typographies-paths))) on-drag-leave - (mf/use-callback + (mf/use-fn (mf/deps dragging?) (fn [event] (on-drag-leave-asset event dragging?))) on-typography-drag-start - (mf/use-callback + (mf/use-fn (mf/deps typography selected-typographies item-ref) (fn [event] (on-asset-drag-start event typography selected-typographies item-ref :typographies identity)))] @@ -1554,21 +1559,21 @@ move-typography (partial dwl/rename-typography file-id) on-drag-enter - (mf/use-callback + (mf/use-fn (mf/deps dragging? prefix selected-typographies-paths) (fn [event] (on-drag-enter-asset-group event dragging? prefix selected-typographies-paths))) on-drag-leave - (mf/use-callback + (mf/use-fn (mf/deps dragging?) (fn [event] (on-drag-leave-asset event dragging?))) - on-drag-over (mf/use-callback #(dom/prevent-default %)) + on-drag-over (mf/use-fn #(dom/prevent-default %)) on-drop - (mf/use-callback + (mf/use-fn (mf/deps dragging? prefix selected-typographies-paths selected-typographies-full move-typography) (fn [event] (on-drop-asset-group event dragging? prefix selected-typographies-paths selected-typographies-full move-typography)))] @@ -1653,7 +1658,7 @@ (seq (:colors selected-assets))) add-typography - (mf/use-callback + (mf/use-fn (mf/deps file-id) (fn [_] (st/emit! (dwl/add-typography txt/default-typography) @@ -1661,7 +1666,7 @@ :asset-type "typography"})))) handle-change - (mf/use-callback + (mf/use-fn (mf/deps file-id) (fn [typography changes] (st/emit! (dwl/update-typography (merge typography changes) file-id)))) @@ -1681,7 +1686,7 @@ ids))) create-group - (mf/use-callback + (mf/use-fn (mf/deps typographies selected-typographies on-clear-selection file-id) (fn [group-name] (on-clear-selection) @@ -1698,7 +1703,7 @@ (st/emit! (dwu/commit-undo-transaction)))) rename-group - (mf/use-callback + (mf/use-fn (mf/deps typographies) (fn [path last-path] (on-clear-selection) @@ -1713,14 +1718,14 @@ (st/emit! (dwu/commit-undo-transaction)))) on-group - (mf/use-callback + (mf/use-fn (mf/deps typographies selected-typographies) (fn [event] (dom/stop-propagation event) (modal/show! :name-group-dialog {:accept create-group}))) on-rename-group - (mf/use-callback + (mf/use-fn (mf/deps typographies) (fn [event path last-path] (dom/stop-propagation event) @@ -1728,7 +1733,7 @@ :last-path last-path :accept rename-group}))) on-ungroup - (mf/use-callback + (mf/use-fn (mf/deps typographies) (fn [path] (on-clear-selection) @@ -1743,7 +1748,7 @@ (st/emit! (dwu/commit-undo-transaction)))) on-context-menu - (mf/use-callback + (mf/use-fn (mf/deps selected-typographies on-clear-selection) (fn [id event] (when local? @@ -1753,7 +1758,7 @@ (swap! menu-state #(open-auto-pos-menu % event))))) on-close-menu - (mf/use-callback + (mf/use-fn (fn [] (swap! menu-state close-auto-pos-menu))) @@ -1766,7 +1771,7 @@ (st/emit! #(assoc-in % [:workspace-global :edit-typography] (:id @state)))) handle-delete-typography - (mf/use-callback + (mf/use-fn (mf/deps @state multi-typographies? multi-assets?) (fn [] (if (or multi-typographies? multi-assets?) @@ -1936,17 +1941,17 @@ components (apply-filters (mf/deref components-ref) filters @reverse-sort?) toggle-sort - (mf/use-callback + (mf/use-fn (fn [_] (swap! reverse-sort? not))) toggle-listing - (mf/use-callback + (mf/use-fn (fn [_] (swap! listing-thumbs? not))) extend-selected-assets - (mf/use-callback + (mf/use-fn (mf/deps selected-assets) (fn [asset-type asset-groups asset-id] (letfn [(flatten-groups @@ -1977,12 +1982,12 @@ (st/emit! (dw/select-assets values asset-type)))))))) unselect-all - (mf/use-callback + (mf/use-fn (fn [] (st/emit! (dw/unselect-all-assets)))) on-asset-click - (mf/use-callback + (mf/use-fn (mf/deps selected-assets) (fn [asset-type asset-groups event asset-id default-click] (cond @@ -2001,7 +2006,7 @@ (default-click event))))) on-assets-delete - (mf/use-callback + (mf/use-fn (mf/deps selected-assets) (fn [] (st/emit! (dwu/start-undo-transaction)) @@ -2136,20 +2141,20 @@ filters (mf/use-state {:term "" :box :all}) on-search-term-change - (mf/use-callback + (mf/use-fn (mf/deps team-id) (fn [event] (let [value (dom/get-target-val event)] (swap! filters assoc :term value)))) on-search-clear-click - (mf/use-callback + (mf/use-fn (mf/deps team-id) (fn [_] (swap! filters assoc :term ""))) on-box-filter-change - (mf/use-callback + (mf/use-fn (mf/deps team-id) (fn [event] (let [value (-> (dom/get-target event) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs index 3f84469fd..eac18cdb1 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs @@ -183,7 +183,7 @@ (let [objects (deref refs/workspace-page-objects) destination (get objects (:destination interaction)) - frames (mf/with-memo [objects] (ctt/get-viewer-frames objects {:all-frames? (not= :navigate (:action-type interaction))})) + frames (mf/with-memo [objects] (ctt/get-viewer-frames objects {:all-frames? true})) overlay-pos-type (:overlay-pos-type interaction) close-click-outside? (:close-click-outside interaction false) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index 47b039812..307b19164 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -12,6 +12,8 @@ [app.main.constants :refer [size-presets]] [app.main.data.workspace :as udw] [app.main.data.workspace.changes :as dch] + [app.main.data.workspace.interactions :as dwi] + [app.main.data.workspace.undo :as dwu] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] @@ -236,7 +238,16 @@ (mf/deps ids) (fn [event] (let [value (-> event dom/get-target dom/checked?)] - (st/emit! (dch/update-shapes ids (fn [shape] (assoc shape :hide-in-viewer (not value)))))))) + (do + (st/emit! (dwu/start-undo-transaction) + (dch/update-shapes ids (fn [shape] (assoc shape :hide-in-viewer (not value))))) + + (when-not value + ;; when a frame is no longer shown in view mode, cannot have + ;; interactions that navigate to it. + (apply st/emit! (map #(dwi/remove-all-interactions-nav-to %) ids))) + + (st/emit! (dwu/commit-undo-transaction)))))) select-all #(-> % (dom/get-target) (.select))]