mirror of
https://github.com/penpot/penpot.git
synced 2026-03-22 10:23:43 +00:00
Merge pull request #8684 from penpot/superalex-fix-embedded-editor-pasting-text-2
🐛 Fix embedded editor pasting text
This commit is contained in:
@@ -41,6 +41,7 @@
|
||||
[app.main.data.workspace.shapes :as dwsh]
|
||||
[app.main.data.workspace.texts :as dwtxt]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.main.data.workspace.wasm-text :as dwwt]
|
||||
[app.main.errors]
|
||||
[app.main.features :as features]
|
||||
[app.main.refs :as refs]
|
||||
@@ -970,10 +971,11 @@
|
||||
text (.-textContent root)
|
||||
content (tc/dom->cljs root)]
|
||||
(when (types.text/valid-content? content)
|
||||
(let [id (uuid/next)
|
||||
width (max 8 (min (* 7 (count text)) 700))
|
||||
height 16
|
||||
(let [id (uuid/next)
|
||||
width (max 8 (min (* 7 (count text)) 700))
|
||||
height 16
|
||||
{:keys [x y]} (calculate-paste-position state)
|
||||
skip-edition? (features/active-feature? state "text-editor-wasm/v1")
|
||||
|
||||
shape {:id id
|
||||
:type :text
|
||||
@@ -985,9 +987,14 @@
|
||||
:grow-type (if (> (count text) 100) :auto-height :auto-width)
|
||||
:content content}
|
||||
undo-id (js/Symbol)]
|
||||
(rx/of (dwu/start-undo-transaction undo-id)
|
||||
(dwsh/create-and-add-shape :text x y shape)
|
||||
(dwu/commit-undo-transaction undo-id))))))))
|
||||
(rx/concat
|
||||
(rx/of (dwu/start-undo-transaction undo-id)
|
||||
(dwsh/create-and-add-shape :text x y shape
|
||||
(when skip-edition? {:skip-edition? true})))
|
||||
(if skip-edition?
|
||||
(rx/of (dwwt/resize-wasm-text-debounce id {:undo-group id
|
||||
:undo-id undo-id}))
|
||||
(rx/of (dwu/commit-undo-transaction undo-id))))))))))
|
||||
|
||||
(defn- paste-text
|
||||
[text]
|
||||
@@ -995,10 +1002,11 @@
|
||||
(ptk/reify ::paste-text
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [id (uuid/next)
|
||||
width (max 8 (min (* 7 (count text)) 700))
|
||||
height 16
|
||||
(let [id (uuid/next)
|
||||
width (max 8 (min (* 7 (count text)) 700))
|
||||
height 16
|
||||
{:keys [x y]} (calculate-paste-position state)
|
||||
skip-edition? (features/active-feature? state "text-editor-wasm/v1")
|
||||
|
||||
shape {:id id
|
||||
:type :text
|
||||
@@ -1011,9 +1019,14 @@
|
||||
:content (as-content text)}
|
||||
undo-id (js/Symbol)]
|
||||
|
||||
(rx/of (dwu/start-undo-transaction undo-id)
|
||||
(dwsh/create-and-add-shape :text x y shape)
|
||||
(dwu/commit-undo-transaction undo-id))))))
|
||||
(rx/concat
|
||||
(rx/of (dwu/start-undo-transaction undo-id)
|
||||
(dwsh/create-and-add-shape :text x y shape
|
||||
(when skip-edition? {:skip-edition? true})))
|
||||
(if skip-edition?
|
||||
(rx/of (dwwt/resize-wasm-text-debounce id {:undo-group id
|
||||
:undo-id undo-id}))
|
||||
(rx/of (dwu/commit-undo-transaction undo-id))))))))
|
||||
|
||||
;; TODO: why not implement it in terms of upload-media-workspace?
|
||||
(defn- paste-svg-text
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
(defn add-shape
|
||||
([shape]
|
||||
(add-shape shape {}))
|
||||
([shape {:keys [no-select? no-update-layout?]}]
|
||||
([shape {:keys [no-select? no-update-layout? skip-edition?]}]
|
||||
|
||||
(cts/check-shape shape)
|
||||
|
||||
@@ -139,7 +139,11 @@
|
||||
(js/Symbol)
|
||||
|
||||
parent-type
|
||||
(cfh/get-shape-type objects (:parent-id shape))]
|
||||
(cfh/get-shape-type objects (:parent-id shape))
|
||||
|
||||
;; Skip edition when using embedded editor (v3) and shape already has content (e.g. paste)
|
||||
start-edition? (and (cfh/text-shape? shape)
|
||||
(not (and skip-edition? (some? (:content shape)))))]
|
||||
|
||||
(rx/concat
|
||||
(rx/of (dwu/start-undo-transaction undo-id)
|
||||
@@ -149,7 +153,7 @@
|
||||
(when-not no-select?
|
||||
(dws/select-shapes (d/ordered-set (:id shape))))
|
||||
(dwu/commit-undo-transaction undo-id))
|
||||
(when (cfh/text-shape? shape)
|
||||
(when start-edition?
|
||||
(->> (rx/of (dwe/start-edition-mode (:id shape)))
|
||||
(rx/observe-on :async)))
|
||||
|
||||
@@ -217,40 +221,42 @@
|
||||
(dwu/commit-undo-transaction undo-id)))))))
|
||||
|
||||
(defn create-and-add-shape
|
||||
[type frame-x frame-y {:keys [width height] :as attrs}]
|
||||
(ptk/reify ::create-and-add-shape
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [vbc (dsh/get-viewport-center state)
|
||||
x (:x attrs (- (:x vbc) (/ width 2)))
|
||||
y (:y attrs (- (:y vbc) (/ height 2)))
|
||||
page-id (:current-page-id state)
|
||||
objects (dsh/lookup-page-objects state page-id)
|
||||
frame-id (-> (dsh/lookup-page-objects state page-id)
|
||||
(ctst/top-nested-frame {:x frame-x :y frame-y}))
|
||||
([type frame-x frame-y attrs]
|
||||
(create-and-add-shape type frame-x frame-y attrs nil))
|
||||
([type frame-x frame-y {:keys [width height] :as attrs} {:keys [skip-edition?]}]
|
||||
(ptk/reify ::create-and-add-shape
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [vbc (dsh/get-viewport-center state)
|
||||
x (:x attrs (- (:x vbc) (/ width 2)))
|
||||
y (:y attrs (- (:y vbc) (/ height 2)))
|
||||
page-id (:current-page-id state)
|
||||
objects (dsh/lookup-page-objects state page-id)
|
||||
frame-id (-> (dsh/lookup-page-objects state page-id)
|
||||
(ctst/top-nested-frame {:x frame-x :y frame-y}))
|
||||
|
||||
selected (dsh/lookup-selected state)
|
||||
base (cfh/get-base-shape objects selected)
|
||||
selected (dsh/lookup-selected state)
|
||||
base (cfh/get-base-shape objects selected)
|
||||
|
||||
parent-id (if (or (and (= 1 (count selected))
|
||||
(cfh/frame-shape? (get objects (first selected))))
|
||||
(empty? selected))
|
||||
frame-id
|
||||
(:parent-id base))
|
||||
parent-id (if (or (and (= 1 (count selected))
|
||||
(cfh/frame-shape? (get objects (first selected))))
|
||||
(empty? selected))
|
||||
frame-id
|
||||
(:parent-id base))
|
||||
|
||||
;; If the parent-id or the frame-id are component-copies, we need to get the first not copy parent
|
||||
parent-id (:id (ctn/get-first-valid-parent objects parent-id)) ;; We don't want to change the structure of component copies
|
||||
frame-id (:id (ctn/get-first-valid-parent objects frame-id))
|
||||
;; If the parent-id or the frame-id are component-copies, we need to get the first not copy parent
|
||||
parent-id (:id (ctn/get-first-valid-parent objects parent-id)) ;; We don't want to change the structure of component copies
|
||||
frame-id (:id (ctn/get-first-valid-parent objects frame-id))
|
||||
|
||||
shape (cts/setup-shape
|
||||
(-> attrs
|
||||
(assoc :type type)
|
||||
(assoc :x x)
|
||||
(assoc :y y)
|
||||
(assoc :frame-id frame-id)
|
||||
(assoc :parent-id parent-id)))]
|
||||
shape (cts/setup-shape
|
||||
(-> attrs
|
||||
(assoc :type type)
|
||||
(assoc :x x)
|
||||
(assoc :y y)
|
||||
(assoc :frame-id frame-id)
|
||||
(assoc :parent-id parent-id)))]
|
||||
|
||||
(rx/of (add-shape shape))))))
|
||||
(rx/of (add-shape shape {:skip-edition? skip-edition?})))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Artboard
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
[app.common.types.modifiers :as ctm]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.data.workspace.modifiers :as dwm]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
[app.render-wasm.api :as wasm.api]
|
||||
[app.render-wasm.api.fonts :as wasm.fonts]
|
||||
[beicon.v2.core :as rx]
|
||||
@@ -76,82 +77,115 @@
|
||||
(rx/empty))))))
|
||||
|
||||
(defn resize-wasm-text-debounce-commit
|
||||
[]
|
||||
(ptk/reify ::resize-wasm-text-debounce-commit
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [ids (get state ::resize-wasm-text-debounce-ids)
|
||||
objects (dsh/lookup-page-objects state)
|
||||
([]
|
||||
(resize-wasm-text-debounce-commit nil nil))
|
||||
([undo-group undo-id]
|
||||
(ptk/reify ::resize-wasm-text-debounce-commit
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [ids (get state ::resize-wasm-text-debounce-ids)
|
||||
objects (dsh/lookup-page-objects state)
|
||||
|
||||
modifiers
|
||||
(reduce
|
||||
(fn [modifiers id]
|
||||
(let [shape (get objects id)]
|
||||
(cond-> modifiers
|
||||
(and (some? shape)
|
||||
(cfh/text-shape? shape)
|
||||
(not= :fixed (:grow-type shape)))
|
||||
(merge (resize-wasm-text-modifiers shape)))))
|
||||
{}
|
||||
ids)]
|
||||
(if (not (empty? modifiers))
|
||||
(rx/of (dwm/apply-wasm-modifiers modifiers))
|
||||
(rx/empty))))))
|
||||
modifiers
|
||||
(reduce
|
||||
(fn [modifiers id]
|
||||
(let [shape (get objects id)]
|
||||
(cond-> modifiers
|
||||
(and (some? shape)
|
||||
(cfh/text-shape? shape)
|
||||
(not= :fixed (:grow-type shape)))
|
||||
(merge (resize-wasm-text-modifiers shape)))))
|
||||
{}
|
||||
ids)
|
||||
|
||||
;; When undo-id is present, extend the current undo transaction instead of
|
||||
;; creating a new one, and commit it after the resize (single undo action).
|
||||
extend-tx? (some? undo-id)
|
||||
apply-opts (cond-> {}
|
||||
(some? undo-group) (assoc :undo-group undo-group)
|
||||
extend-tx? (assoc :undo-transation? false))]
|
||||
(cond
|
||||
(not (empty? modifiers))
|
||||
(if extend-tx?
|
||||
(rx/concat
|
||||
(rx/of (dwm/apply-wasm-modifiers modifiers apply-opts))
|
||||
(rx/of (dwu/commit-undo-transaction undo-id)))
|
||||
(rx/of (dwm/apply-wasm-modifiers modifiers apply-opts)))
|
||||
|
||||
extend-tx?
|
||||
;; No resize needed (e.g. :fixed grow-type) but we must commit the add
|
||||
(rx/of (dwu/commit-undo-transaction undo-id))
|
||||
|
||||
:else
|
||||
(rx/empty)))))))
|
||||
|
||||
;; This event will debounce the resize events so, if there are many, they
|
||||
;; are processed at the same time and not one-by-one. This will improve
|
||||
;; performance because it's better to make only one layout calculation instead
|
||||
;; of (potentialy) hundreds.
|
||||
(defn resize-wasm-text-debounce-inner
|
||||
[id]
|
||||
(let [cur-event (js/Symbol)]
|
||||
(ptk/reify ::resize-wasm-text-debounce-inner
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update ::resize-wasm-text-debounce-ids (fnil conj []) id)
|
||||
(cond-> (nil? (::resize-wasm-text-debounce-event state))
|
||||
(assoc ::resize-wasm-text-debounce-event cur-event))))
|
||||
([id]
|
||||
(resize-wasm-text-debounce-inner id nil))
|
||||
([id {:keys [undo-group undo-id]}]
|
||||
(let [cur-event (js/Symbol)]
|
||||
(ptk/reify ::resize-wasm-text-debounce-inner
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update ::resize-wasm-text-debounce-ids (fnil conj []) id)
|
||||
(cond-> (nil? (::resize-wasm-text-debounce-event state))
|
||||
(assoc ::resize-wasm-text-debounce-event cur-event))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(if (= (::resize-wasm-text-debounce-event state) cur-event)
|
||||
(let [stopper (->> stream (rx/filter (ptk/type? :app.main.data.workspace/finalize)))]
|
||||
(rx/concat
|
||||
(rx/merge
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::resize-wasm-text-debounce-inner))
|
||||
(rx/debounce 40)
|
||||
(rx/take 1)
|
||||
(rx/map #(resize-wasm-text-debounce-commit))
|
||||
(rx/take-until stopper))
|
||||
(rx/of (resize-wasm-text-debounce-inner id)))
|
||||
(rx/of #(dissoc %
|
||||
::resize-wasm-text-debounce-ids
|
||||
::resize-wasm-text-debounce-event))))
|
||||
(rx/empty))))))
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(if (= (::resize-wasm-text-debounce-event state) cur-event)
|
||||
(let [stopper (->> stream (rx/filter (ptk/type? :app.main.data.workspace/finalize)))]
|
||||
(rx/concat
|
||||
(rx/merge
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::resize-wasm-text-debounce-inner))
|
||||
(rx/debounce 40)
|
||||
(rx/take 1)
|
||||
(rx/map (fn [evt]
|
||||
(resize-wasm-text-debounce-commit
|
||||
(some-> evt meta :undo-group)
|
||||
(some-> evt meta :undo-id))))
|
||||
(rx/take-until stopper))
|
||||
(rx/of (with-meta
|
||||
(resize-wasm-text-debounce-inner id)
|
||||
{:undo-group undo-group :undo-id undo-id})))
|
||||
(rx/of #(dissoc %
|
||||
::resize-wasm-text-debounce-ids
|
||||
::resize-wasm-text-debounce-event))))
|
||||
(rx/empty)))))))
|
||||
|
||||
(defn resize-wasm-text-debounce
|
||||
[id]
|
||||
(ptk/reify ::resize-wasm-text-debounce
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (dsh/lookup-page-objects state page-id)
|
||||
content (dm/get-in objects [id :content])
|
||||
fonts (wasm.fonts/get-content-fonts content)
|
||||
([id]
|
||||
(resize-wasm-text-debounce id nil))
|
||||
([id {:keys [undo-group undo-id] :as opts}]
|
||||
(ptk/reify ::resize-wasm-text-debounce
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (dsh/lookup-page-objects state page-id)
|
||||
content (dm/get-in objects [id :content])
|
||||
fonts (wasm.fonts/get-content-fonts content)
|
||||
|
||||
fonts-loaded?
|
||||
(->> fonts
|
||||
(every?
|
||||
(fn [font]
|
||||
(let [font-data (wasm.fonts/make-font-data font)]
|
||||
(wasm.fonts/font-stored? font-data (:emoji? font-data))))))]
|
||||
fonts-loaded?
|
||||
(->> fonts
|
||||
(every?
|
||||
(fn [font]
|
||||
(let [font-data (wasm.fonts/make-font-data font)]
|
||||
(wasm.fonts/font-stored? font-data (:emoji? font-data))))))]
|
||||
|
||||
(if (not fonts-loaded?)
|
||||
(->> (rx/of (resize-wasm-text-debounce id))
|
||||
(rx/delay 20))
|
||||
(rx/of (resize-wasm-text-debounce-inner id)))))))
|
||||
(if (not fonts-loaded?)
|
||||
(->> (rx/of (resize-wasm-text-debounce id opts))
|
||||
(rx/delay 20))
|
||||
(let [pass-opts (when (or (some? undo-group) (some? undo-id))
|
||||
(cond-> {}
|
||||
(some? undo-group) (assoc :undo-group undo-group)
|
||||
(some? undo-id) (assoc :undo-id undo-id)))]
|
||||
(rx/of (resize-wasm-text-debounce-inner id pass-opts)))))))))
|
||||
|
||||
(defn resize-wasm-text-all
|
||||
"Resize all text shapes (auto-width/auto-height) from a collection of ids."
|
||||
|
||||
Reference in New Issue
Block a user