Merge pull request #8580 from penpot/niwinz-staging-fix-paste-issue

🐛 Fix crash when pasting non-map transit clipboard data
This commit is contained in:
Alejandro Alonso
2026-03-13 08:33:19 +01:00
committed by GitHub
3 changed files with 40 additions and 23 deletions

View File

@@ -40,6 +40,7 @@
- Fix 'not ISeqable' error when entering float values in layout item and opacity inputs [Github #8569](https://github.com/penpot/penpot/pull/8569)
- Fix crash in select component when options vector is empty [Github #8578](https://github.com/penpot/penpot/pull/8578)
- Fix scroll on colorpicker [Taiga #13623](https://tree.taiga.io/project/penpot/issue/13623)
- Fix crash when pasting non-map transit clipboard data [Github #8580](https://github.com/penpot/penpot/pull/8580)
## 2.13.3

View File

@@ -258,33 +258,39 @@
#js {:decodeTransit t/decode-str
:allowHTMLPaste (features/active-feature? @st/state "text-editor/v2-html-paste")})
(defn create-paste-from-blob
(defn- create-paste-from-blob
[in-viewport?]
(fn [blob]
(let [type (.-type blob)
result (cond
(= type "image/svg+xml")
(->> (rx/from (.text blob))
(rx/map paste-svg-text))
(let [type (.-type blob)]
(cond
(= type "image/svg+xml")
(->> (rx/from (.text blob))
(rx/map paste-svg-text))
(some #(= type %) clipboard/image-types)
(rx/of (paste-image blob))
(some #(= type %) clipboard/image-types)
(rx/of (paste-image blob))
(= type "text/html")
(->> (rx/from (.text blob))
(rx/map paste-html-text))
(= type "text/html")
(->> (rx/from (.text blob))
(rx/map paste-html-text))
(= type "application/transit+json")
(->> (rx/from (.text blob))
(rx/map (fn [text]
(let [transit-data (t/decode-str text)]
(assoc transit-data :in-viewport in-viewport?))))
(rx/map paste-transit-shapes))
(= type "application/transit+json")
(->> (rx/from (.text blob))
(rx/map t/decode-str)
(rx/filter map?)
(rx/map
(fn [pdata]
(assoc pdata :in-viewport in-viewport?)))
(rx/mapcat
(fn [pdata]
(case (:type pdata)
:copied-props (rx/of (paste-transit-props pdata))
:copied-shapes (rx/of (paste-transit-shapes pdata))
(rx/empty)))))
:else
(->> (rx/from (.text blob))
(rx/map paste-text)))]
result)))
:else
(->> (rx/from (.text blob))
(rx/map paste-text))))))
(def default-paste-from-blob (create-paste-from-blob false))

View File

@@ -30,6 +30,15 @@ const exclusiveTypes = [
* @property {boolean} [allowHTMLPaste]
*/
const looksLikeJSON = (str) => {
if (typeof str !== 'string') return false;
const trimmed = str.trim();
return (
(trimmed.startsWith('{') && trimmed.endsWith('}')) ||
(trimmed.startsWith('[') && trimmed.endsWith(']'))
);
};
/**
*
* @param {string} text
@@ -39,13 +48,14 @@ const exclusiveTypes = [
*/
function parseText(text, options) {
options = options || {};
const decodeTransit = options["decodeTransit"];
if (decodeTransit) {
if (decodeTransit && looksLikeJSON(text)) {
try {
decodeTransit(text);
return new Blob([text], { type: "application/transit+json" });
} catch (_error) {
// NOOP
return new Blob([text], { type: "text/plain" });
}
}