mirror of https://github.com/penpot/penpot.git
Merge pull request #7735 from penpot/superalex-fix-create-empty-text
🐛 Fix some text issues
This commit is contained in:
commit
3f05dae455
|
|
@ -96,6 +96,16 @@
|
|||
(->> (rx/from ids)
|
||||
(rx/map resize-wasm-text)))))
|
||||
|
||||
;; -- Content helpers
|
||||
|
||||
(defn- v2-content-has-text?
|
||||
[content]
|
||||
(boolean
|
||||
(when content
|
||||
(some (fn [node]
|
||||
(not (str/blank? (:text node ""))))
|
||||
(txt/node-seq txt/is-text-node? content)))))
|
||||
|
||||
;; -- Editor
|
||||
|
||||
(defn update-editor
|
||||
|
|
@ -948,28 +958,34 @@
|
|||
(let [objects (dsh/lookup-page-objects state)
|
||||
shape (get objects id)
|
||||
new-shape? (nil? (:content shape))]
|
||||
(rx/of
|
||||
(dwsh/update-shapes
|
||||
[id]
|
||||
(fn [shape]
|
||||
(let [new-shape (-> shape
|
||||
(assoc :content content)
|
||||
(cond-> (and update-name? (some? name))
|
||||
(assoc :name name)))]
|
||||
new-shape))
|
||||
{:undo-group (when new-shape? id)})
|
||||
(rx/concat
|
||||
(rx/of
|
||||
(dwsh/update-shapes
|
||||
[id]
|
||||
(fn [shape]
|
||||
(let [new-shape (-> shape
|
||||
(assoc :content content)
|
||||
(cond-> (and update-name? (some? name))
|
||||
(assoc :name name)))]
|
||||
new-shape))
|
||||
{:undo-group (when new-shape? id)})
|
||||
|
||||
(if (and (not= :fixed (:grow-type shape)) finalize?)
|
||||
(dwm/apply-wasm-modifiers
|
||||
(resize-wasm-text-modifiers shape content)
|
||||
{:undo-group (when new-shape? id)})
|
||||
(if (and (not= :fixed (:grow-type shape)) finalize?)
|
||||
(dwm/apply-wasm-modifiers
|
||||
(resize-wasm-text-modifiers shape content)
|
||||
{:undo-group (when new-shape? id)})
|
||||
|
||||
(dwm/set-wasm-modifiers
|
||||
(resize-wasm-text-modifiers shape content)
|
||||
{:undo-group (when new-shape? id)}))
|
||||
(dwm/set-wasm-modifiers
|
||||
(resize-wasm-text-modifiers shape content)
|
||||
{:undo-group (when new-shape? id)})))
|
||||
|
||||
(when finalize?
|
||||
(dwt/finish-transform))))
|
||||
(rx/concat
|
||||
(when (and (not (v2-content-has-text? content)) (some? id))
|
||||
(rx/of
|
||||
(dws/deselect-shape id)
|
||||
(dwsh/delete-shapes #{id})))
|
||||
(rx/of (dwt/finish-transform))))))
|
||||
|
||||
(let [objects (dsh/lookup-page-objects state)
|
||||
shape (get objects id)
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
[app.render-wasm.wasm :as wasm]
|
||||
[app.util.debug :as dbg]
|
||||
[app.util.functions :as fns]
|
||||
[app.util.text.content :as tc]
|
||||
[beicon.v2.core :as rx]
|
||||
[promesa.core :as p]
|
||||
[rumext.v2 :as mf]))
|
||||
|
|
@ -106,6 +107,14 @@
|
|||
(reset! pending-render false)
|
||||
(render ts)))))
|
||||
|
||||
|
||||
(defn- ensure-text-content
|
||||
"Guarantee that the shape always sends a valid text tree to WASM. When the
|
||||
content is nil (freshly created text) we fall back to
|
||||
tc/default-text-content so the renderer receives typography information."
|
||||
[content]
|
||||
(or content (tc/v2-default-text-content)))
|
||||
|
||||
(defn use-shape
|
||||
[id]
|
||||
(when wasm/context-initialized?
|
||||
|
|
@ -850,7 +859,10 @@
|
|||
blend-mode (get shape :blend-mode)
|
||||
opacity (get shape :opacity)
|
||||
hidden (get shape :hidden)
|
||||
content (get shape :content)
|
||||
content (let [content (get shape :content)]
|
||||
(if (= type :text)
|
||||
(ensure-text-content content)
|
||||
content))
|
||||
bool-type (get shape :bool-type)
|
||||
grow-type (get shape :grow-type)
|
||||
blur (get shape :blur)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
(ns app.util.text.content
|
||||
(:require
|
||||
[app.common.types.text :as txt]
|
||||
[app.main.refs :as refs]
|
||||
[app.util.text.content.from-dom :as fd]
|
||||
[app.util.text.content.to-dom :as td]))
|
||||
|
||||
|
|
@ -18,3 +20,22 @@
|
|||
"Sets the editor content from a CLJS structure"
|
||||
[root]
|
||||
(td/create-root root))
|
||||
|
||||
(defn v2-default-text-content
|
||||
"Build the base text tree (root -> paragraph-set -> paragraph -> span) with the
|
||||
current default typography. Used by the V2 editor/WASM path when a shape is
|
||||
created with no content yet."
|
||||
[]
|
||||
(let [default-font (deref refs/default-font)
|
||||
text-defaults (merge (txt/get-default-text-attrs) default-font)
|
||||
default-span (merge {:text ""}
|
||||
(select-keys text-defaults txt/text-node-attrs))
|
||||
default-paragraph (merge {:type "paragraph"
|
||||
:children [default-span]}
|
||||
(select-keys text-defaults txt/paragraph-attrs))
|
||||
default-paragraph-set {:type "paragraph-set"
|
||||
:children [default-paragraph]}]
|
||||
(merge {:type "root"
|
||||
:children [default-paragraph-set]}
|
||||
txt/default-root-attrs
|
||||
(select-keys text-defaults txt/root-attrs))))
|
||||
|
|
|
|||
|
|
@ -428,8 +428,17 @@ pub fn resize_matrix(
|
|||
new_height: f32,
|
||||
) -> Matrix {
|
||||
let mut result = Matrix::default();
|
||||
let scale_width = new_width / child_bounds.width();
|
||||
let scale_height = new_height / child_bounds.height();
|
||||
|
||||
let safe_scale = |value: f32, base: f32| -> f32 {
|
||||
if !value.is_finite() || !base.is_finite() || is_close_to(base, 0.0) {
|
||||
1.0
|
||||
} else {
|
||||
value / base
|
||||
}
|
||||
};
|
||||
|
||||
let scale_width = safe_scale(new_width, child_bounds.width());
|
||||
let scale_height = safe_scale(new_height, child_bounds.height());
|
||||
|
||||
let center = child_bounds.center();
|
||||
let mut parent_transform = parent_bounds.transform_matrix().unwrap_or_default();
|
||||
|
|
|
|||
|
|
@ -508,8 +508,80 @@ impl TextContent {
|
|||
self.set_layout_from_result(result, selrect.width(), selrect.height());
|
||||
}
|
||||
}
|
||||
|
||||
if self.is_empty() {
|
||||
let (placeholder_width, placeholder_height) = self.placeholder_dimensions(selrect);
|
||||
self.size.width = placeholder_width;
|
||||
self.size.height = placeholder_height;
|
||||
self.size.max_width = placeholder_width;
|
||||
}
|
||||
|
||||
self.size
|
||||
}
|
||||
|
||||
/// Return true when the content represents a freshly created empty text.
|
||||
/// We consider it empty only if there is exactly one paragraph with a single
|
||||
/// span whose text buffer is empty. Any additional paragraphs or characters
|
||||
/// mean the user has already entered content.
|
||||
fn is_empty(&self) -> bool {
|
||||
if self.paragraphs.len() != 1 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let paragraph = match self.paragraphs.first() {
|
||||
Some(paragraph) => paragraph,
|
||||
None => return true,
|
||||
};
|
||||
if paragraph.children().len() != 1 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let span = match paragraph.children().first() {
|
||||
Some(span) => span,
|
||||
None => return true,
|
||||
};
|
||||
|
||||
span.text.is_empty()
|
||||
}
|
||||
|
||||
/// Compute the placeholder size used while the text is still empty. We ask
|
||||
/// Skia to measure a single glyph using the span's typography so the editor
|
||||
/// shows a caret-sized box that reflects the selected font, size and spacing.
|
||||
/// If that fails we fall back to the previous WASM size or the incoming
|
||||
/// selrect dimensions.
|
||||
fn placeholder_dimensions(&self, selrect: Rect) -> (f32, f32) {
|
||||
if let Some(paragraph) = self.paragraphs.first() {
|
||||
if let Some(span) = paragraph.children().first() {
|
||||
let fonts = get_font_collection();
|
||||
let fallback_fonts = get_fallback_fonts();
|
||||
let paragraph_style = paragraph.paragraph_to_style();
|
||||
let mut builder = ParagraphBuilder::new(¶graph_style, fonts);
|
||||
|
||||
let text_style = span.to_style(
|
||||
&self.bounds(),
|
||||
fallback_fonts,
|
||||
false,
|
||||
paragraph.line_height(),
|
||||
);
|
||||
|
||||
builder.push_style(&text_style);
|
||||
builder.add_text("0");
|
||||
|
||||
let mut paragraph_layout = builder.build();
|
||||
paragraph_layout.layout(f32::MAX);
|
||||
|
||||
let width = paragraph_layout.max_intrinsic_width();
|
||||
let height = paragraph_layout.height();
|
||||
|
||||
return (width, height);
|
||||
}
|
||||
}
|
||||
|
||||
let fallback_width = selrect.width().max(self.size.width);
|
||||
let fallback_height = selrect.height().max(self.size.height);
|
||||
|
||||
(fallback_width, fallback_height)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TextContent {
|
||||
|
|
|
|||
Loading…
Reference in New Issue