mirror of
https://github.com/penpot/penpot.git
synced 2026-08-01 19:06:18 +00:00
Merge pull request #8302 from penpot/azazeln28-issue-13124-text-not-restored-undoing
🐛 Fix text not restored on ctrl+z
This commit is contained in:
commit
cf2b40a097
@ -46,6 +46,7 @@
|
|||||||
(def ^function create-editor editor.v2/create)
|
(def ^function create-editor editor.v2/create)
|
||||||
(def ^function set-editor-root! editor.v2/setRoot)
|
(def ^function set-editor-root! editor.v2/setRoot)
|
||||||
(def ^function get-editor-root editor.v2/getRoot)
|
(def ^function get-editor-root editor.v2/getRoot)
|
||||||
|
(def ^function is-empty? editor.v2/isEmpty)
|
||||||
(def ^function dispose! editor.v2/dispose)
|
(def ^function dispose! editor.v2/dispose)
|
||||||
|
|
||||||
(declare v2-update-text-shape-content)
|
(declare v2-update-text-shape-content)
|
||||||
@ -901,15 +902,22 @@
|
|||||||
(update-in state [:workspace-text-modifier shape-id] {:position-data position-data}))))
|
(update-in state [:workspace-text-modifier shape-id] {:position-data position-data}))))
|
||||||
|
|
||||||
(defn v2-update-text-shape-content
|
(defn v2-update-text-shape-content
|
||||||
[id content & {:keys [update-name? name finalize?]
|
[id content & {:keys [update-name? name finalize? save-undo?]
|
||||||
:or {update-name? false name nil finalize? false}}]
|
:or {update-name? false name nil finalize? false save-undo? true}}]
|
||||||
(ptk/reify ::v2-update-text-shape-content
|
(ptk/reify ::v2-update-text-shape-content
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(if (features/active-feature? state "render-wasm/v1")
|
(if (features/active-feature? state "render-wasm/v1")
|
||||||
(let [objects (dsh/lookup-page-objects state)
|
(let [objects (dsh/lookup-page-objects state)
|
||||||
shape (get objects id)
|
shape (get objects id)
|
||||||
new-shape? (nil? (:content shape))]
|
new-shape? (nil? (:content shape))
|
||||||
|
prev-content (:content shape)
|
||||||
|
has-prev-content? (not (nil? (:prev-content shape)))
|
||||||
|
has-content? (when-not new-shape?
|
||||||
|
(v2-content-has-text? content))
|
||||||
|
did-has-content? (when-not new-shape?
|
||||||
|
(v2-content-has-text? prev-content))]
|
||||||
|
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(rx/of
|
(rx/of
|
||||||
(dwsh/update-shapes
|
(dwsh/update-shapes
|
||||||
@ -917,10 +925,16 @@
|
|||||||
(fn [shape]
|
(fn [shape]
|
||||||
(let [new-shape (-> shape
|
(let [new-shape (-> shape
|
||||||
(assoc :content content)
|
(assoc :content content)
|
||||||
|
(cond-> (and has-content?
|
||||||
|
has-prev-content?)
|
||||||
|
(dissoc :prev-content))
|
||||||
|
(cond-> (and did-has-content?
|
||||||
|
(not has-content?))
|
||||||
|
(assoc :prev-content prev-content))
|
||||||
(cond-> (and update-name? (some? name))
|
(cond-> (and update-name? (some? name))
|
||||||
(assoc :name name)))]
|
(assoc :name name)))]
|
||||||
new-shape))
|
new-shape))
|
||||||
{:undo-group (when new-shape? id)})
|
{:save-undo? save-undo? :undo-group (when new-shape? id)})
|
||||||
|
|
||||||
(if (and (not= :fixed (:grow-type shape)) finalize?)
|
(if (and (not= :fixed (:grow-type shape)) finalize?)
|
||||||
(dwm/apply-wasm-modifiers
|
(dwm/apply-wasm-modifiers
|
||||||
@ -933,8 +947,16 @@
|
|||||||
|
|
||||||
(when finalize?
|
(when finalize?
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(when (and (not (v2-content-has-text? content)) (some? id))
|
(when (and (not has-content?) (some? id))
|
||||||
(rx/of
|
(rx/of
|
||||||
|
(when has-prev-content?
|
||||||
|
(dwsh/update-shapes
|
||||||
|
[id]
|
||||||
|
(fn [shape]
|
||||||
|
(let [new-shape (-> shape
|
||||||
|
(assoc :content (:prev-content shape)))]
|
||||||
|
new-shape))
|
||||||
|
{:save-undo? false}))
|
||||||
(dws/deselect-shape id)
|
(dws/deselect-shape id)
|
||||||
(dwsh/delete-shapes #{id})))
|
(dwsh/delete-shapes #{id})))
|
||||||
(rx/of (dwt/finish-transform))))))
|
(rx/of (dwt/finish-transform))))))
|
||||||
|
|||||||
@ -117,7 +117,8 @@
|
|||||||
(st/emit! (dwt/v2-update-text-shape-content shape-id content
|
(st/emit! (dwt/v2-update-text-shape-content shape-id content
|
||||||
:update-name? update-name?
|
:update-name? update-name?
|
||||||
:name generated-name
|
:name generated-name
|
||||||
:finalize? true))))
|
:finalize? true
|
||||||
|
:save-undo? false))))
|
||||||
|
|
||||||
(let [container-node (mf/ref-val container-ref)]
|
(let [container-node (mf/ref-val container-ref)]
|
||||||
(dom/set-style! container-node "opacity" 0)))
|
(dom/set-style! container-node "opacity" 0)))
|
||||||
@ -135,15 +136,21 @@
|
|||||||
on-needs-layout
|
on-needs-layout
|
||||||
(fn []
|
(fn []
|
||||||
(when-let [content (content/dom->cljs (dwt/get-editor-root instance))]
|
(when-let [content (content/dom->cljs (dwt/get-editor-root instance))]
|
||||||
(st/emit! (dwt/v2-update-text-shape-content shape-id content :update-name? true)))
|
(st/emit! (dwt/v2-update-text-shape-content shape-id content
|
||||||
|
:update-name? true
|
||||||
|
:save-undo? false)))
|
||||||
;; FIXME: We need to find a better way to trigger layout changes.
|
;; FIXME: We need to find a better way to trigger layout changes.
|
||||||
#_(st/emit!
|
#_(st/emit!
|
||||||
(dwt/v2-update-text-shape-position-data shape-id [])))
|
(dwt/v2-update-text-shape-position-data shape-id [])))
|
||||||
|
|
||||||
on-change
|
on-change
|
||||||
(fn []
|
(fn []
|
||||||
(when-let [content (content/dom->cljs (dwt/get-editor-root instance))]
|
(let [is-empty? (dwt/is-empty? instance)
|
||||||
(st/emit! (dwt/v2-update-text-shape-content shape-id content :update-name? true))))
|
save-undo? (not is-empty?)]
|
||||||
|
(when-let [content (content/dom->cljs (dwt/get-editor-root instance))]
|
||||||
|
(st/emit! (dwt/v2-update-text-shape-content shape-id content
|
||||||
|
:update-name? true
|
||||||
|
:save-undo? save-undo?)))))
|
||||||
|
|
||||||
on-clipboard-change
|
on-clipboard-change
|
||||||
(fn [event]
|
(fn [event]
|
||||||
@ -247,7 +254,7 @@
|
|||||||
:ref container-ref
|
:ref container-ref
|
||||||
:data-testid "text-editor-container"
|
:data-testid "text-editor-container"
|
||||||
:style {:width "var(--editor-container-width)"
|
:style {:width "var(--editor-container-width)"
|
||||||
:height "var(--editor-container-height)"}
|
:height "var(--editor-container-height)"}}
|
||||||
;; We hide the editor when is blurred because otherwise the
|
;; We hide the editor when is blurred because otherwise the
|
||||||
;; selection won't let us see the underlying text. Use opacity
|
;; selection won't let us see the underlying text. Use opacity
|
||||||
;; because display or visibility won't allow to recover focus
|
;; because display or visibility won't allow to recover focus
|
||||||
@ -256,7 +263,7 @@
|
|||||||
;; IMPORTANT! This is now done through DOM mutations (see
|
;; IMPORTANT! This is now done through DOM mutations (see
|
||||||
;; on-blur and on-focus) but I keep this for future references.
|
;; on-blur and on-focus) but I keep this for future references.
|
||||||
;; :opacity (when @blurred 0)}}
|
;; :opacity (when @blurred 0)}}
|
||||||
}
|
|
||||||
[:div
|
[:div
|
||||||
{:class (dm/str
|
{:class (dm/str
|
||||||
"mousetrap "
|
"mousetrap "
|
||||||
|
|||||||
@ -32,7 +32,8 @@
|
|||||||
"This function adds units to style values"
|
"This function adds units to style values"
|
||||||
[k v]
|
[k v]
|
||||||
(cond
|
(cond
|
||||||
(and (or (= k :font-size)
|
(and (keyword? k)
|
||||||
|
(or (= k :font-size)
|
||||||
(= k :letter-spacing))
|
(= k :letter-spacing))
|
||||||
(not= (str/slice v -2) "px"))
|
(not= (str/slice v -2) "px"))
|
||||||
(str v "px")
|
(str v "px")
|
||||||
|
|||||||
@ -326,7 +326,9 @@ export class TextEditor extends EventTarget {
|
|||||||
* @param {FocusEvent} e
|
* @param {FocusEvent} e
|
||||||
*/
|
*/
|
||||||
#onBlur = (e) => {
|
#onBlur = (e) => {
|
||||||
this.#changeController.notifyImmediately();
|
if (!this.isEmpty) {
|
||||||
|
this.#changeController.notifyImmediately();
|
||||||
|
}
|
||||||
this.#selectionController.saveSelection();
|
this.#selectionController.saveSelection();
|
||||||
this.dispatchEvent(new FocusEvent(e.type, e));
|
this.dispatchEvent(new FocusEvent(e.type, e));
|
||||||
};
|
};
|
||||||
@ -683,13 +685,26 @@ export function createRootFromString(string) {
|
|||||||
* Returns true if the passed object is a TextEditor
|
* Returns true if the passed object is a TextEditor
|
||||||
* instance.
|
* instance.
|
||||||
*
|
*
|
||||||
* @param {*} instance
|
* @param {TextEditor} instance
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function isTextEditor(instance) {
|
export function isTextEditor(instance) {
|
||||||
return instance instanceof TextEditor;
|
return instance instanceof TextEditor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the TextEditor is empty.
|
||||||
|
*
|
||||||
|
* @param {TextEditor} instance
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isEmpty(instance) {
|
||||||
|
if (isTextEditor(instance)) {
|
||||||
|
return instance.isEmpty;
|
||||||
|
}
|
||||||
|
throw new TypeError('Instance is not a TextEditor');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the root element of a TextEditor
|
* Returns the root element of a TextEditor
|
||||||
* instance.
|
* instance.
|
||||||
@ -701,7 +716,7 @@ export function getRoot(instance) {
|
|||||||
if (isTextEditor(instance)) {
|
if (isTextEditor(instance)) {
|
||||||
return instance.root;
|
return instance.root;
|
||||||
}
|
}
|
||||||
return null;
|
throw new TypeError("Instance is not a TextEditor");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -714,9 +729,9 @@ export function getRoot(instance) {
|
|||||||
export function setRoot(instance, root) {
|
export function setRoot(instance, root) {
|
||||||
if (isTextEditor(instance)) {
|
if (isTextEditor(instance)) {
|
||||||
instance.root = root;
|
instance.root = root;
|
||||||
|
return instance;
|
||||||
}
|
}
|
||||||
|
throw new TypeError("Instance is not a TextEditor");
|
||||||
return instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -741,7 +756,7 @@ export function getCurrentStyle(instance) {
|
|||||||
if (isTextEditor(instance)) {
|
if (isTextEditor(instance)) {
|
||||||
return instance.currentStyle;
|
return instance.currentStyle;
|
||||||
}
|
}
|
||||||
return null;
|
throw new TypeError("Instance is not a TextEditor");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -756,7 +771,7 @@ export function applyStylesToSelection(instance, styles) {
|
|||||||
if (isTextEditor(instance)) {
|
if (isTextEditor(instance)) {
|
||||||
return instance.applyStylesToSelection(styles);
|
return instance.applyStylesToSelection(styles);
|
||||||
}
|
}
|
||||||
return null;
|
throw new TypeError("Instance is not a TextEditor");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -770,7 +785,7 @@ export function dispose(instance) {
|
|||||||
if (isTextEditor(instance)) {
|
if (isTextEditor(instance)) {
|
||||||
return instance.dispose();
|
return instance.dispose();
|
||||||
}
|
}
|
||||||
return null;
|
throw new TypeError("Instance is not a TextEditor");
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TextEditor;
|
export default TextEditor;
|
||||||
|
|||||||
@ -54,8 +54,12 @@ export class ChangeController extends EventTarget {
|
|||||||
return this.#hasPendingChanges;
|
return this.#hasPendingChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles timeout.
|
||||||
|
*/
|
||||||
#onTimeout = () => {
|
#onTimeout = () => {
|
||||||
this.dispatchEvent(new Event("change"));
|
this.dispatchEvent(new Event("change"));
|
||||||
|
this.#hasPendingChanges = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user