Repository: penpot/penpot
File: frontend/src/uxbox/main/data/workspace.cljs (ClojureScript)

Code before:
               :obj reframed-obj}))

          (prepare-frame-change [objects obj delta]
            (let [frame-id (uuid/next)
                  frame-name (impl-generate-unique-name objects (:name obj))
                  sch (->> (map #(get objects %) (:shapes obj))
                           (map #(prepare-shape-change objects % delta frame-id)))
                  renamed-frame (-> obj
                                    (assoc :id frame-id)
                                    (assoc :name frame-name)
                                    (assoc :frame-id uuid/zero)
                                    (assoc :shapes (mapv :id sch)))
                  moved-frame (geom/move renamed-frame delta)
                  fch {:type :add-obj
                       :id frame-id
                       :frame-id uuid/zero
                       :obj moved-frame}]
              (d/concat [fch] sch)))]

  (ptk/reify ::paste-impl
    ptk/WatchEvent
    (watch [_ state stream]
      (let [selected-objs (map #(get objects %) selected)
            orig-pos (geom/selection-rect selected-objs)
            mouse-pos @ms/mouse-position
            delta {:x (- (:x mouse-pos) (:x orig-pos))
                   :y (- (:y mouse-pos) (:y orig-pos))}

            rchanges (prepare-changes state delta)
            uchanges (map (fn [ch]
                            {:type :del-obj
                             :id (:id ch)})
                          rchanges)]
        (rx/of (commit-changes (vec rchanges)
                               (vec (reverse uchanges))
                               {:commit-local? true})
               (select-pasted-objs rchanges)))))))

(def paste
  (ptk/reify ::paste
    ptk/WatchEvent
    (watch [_ state stream]
      (->> (rx/from (wapi/read-from-clipboard))
           (rx/filter #(= :copied-shapes (:type %)))
           (rx/pr-log "pasting:")
           (rx/map :data)
           (rx/map paste-impl)
           (rx/catch (fn [err]
                       (js/console.error "Clipboard blocked:" err)
                       (rx/empty)))))))


Review comment (suggestion):
Deberias construir una instancia de `uxbox.util.geom.point` en vez de un mapa (aqui tecnicamenre es irelecante es puramente por usar siempre el mismo tipo) pero en otros casos esos tipos son mas eficientes tanto en memoria como en acceso a sus propiedades

Code after:

          (prepare-frame-change [objects obj delta]
            (let [frame-id (uuid/next)
                  frame-name (impl-generate-unique-name objects (:name obj))
                  sch (->> (map #(get objects %) (:shapes obj))
                           (map #(prepare-shape-change objects % delta frame-id)))
                  renamed-frame (-> obj
                                    (assoc :id frame-id)
                                    (assoc :name frame-name)
                                    (assoc :frame-id uuid/zero)
                                    (assoc :shapes (mapv :id sch)))
                  moved-frame (geom/move renamed-frame delta)
                  fch {:type :add-obj
                       :id frame-id
                       :frame-id uuid/zero
                       :obj moved-frame}]
              (d/concat [fch] sch)))]

  (ptk/reify ::paste-impl
    ptk/WatchEvent
    (watch [_ state stream]
      (let [selected-objs (map #(get objects %) selected)
            wrapper (geom/selection-rect selected-objs)
            orig-pos (gpt/point (:x1 wrapper) (:y1 wrapper))
            mouse-pos @ms/mouse-position
            delta (gpt/subtract mouse-pos orig-pos)

            rchanges (prepare-changes state delta)
            uchanges (map (fn [ch]
                            {:type :del-obj
                             :id (:id ch)})
                          rchanges)]
        (rx/of (commit-changes (vec rchanges)
                               (vec (reverse uchanges))
                               {:commit-local? true})
               (select-pasted-objs rchanges)))))))

(def paste
  (ptk/reify ::paste
    ptk/WatchEvent
    (watch [_ state stream]
      (->> (rx/from (wapi/read-from-clipboard))
           (rx/filter #(= :copied-shapes (:type %)))
           (rx/pr-log "pasting:")
           (rx/map :data)
           (rx/map paste-impl)
           (rx/catch (fn [err]
                       (js/console.error "Clipboard blocked:" err)
                       (rx/empty)))))))

(defn select-pasted-objs