Skip to content

Commit fa06efa

Browse files
authored
♻️ Migrate fo-text and html-text renderers to modern component syntax (penpot#9385)
Step toward issue penpot#9260 (incremental migration of legacy UI components to the modern `*`-suffixed syntax, removing the per-render JS-to-Clojure props conversion overhead). Twin namespaces with parallel structure: each defines six components that drive a recursive text rendering pass over the editor's content tree (root -> paragraph-set -> paragraph -> node -> text). Both files were uniformly legacy: every component carried `::mf/wrap-props false` and read its props with `(obj/get props "key")`. None had `::mf/register`, `unchecked-get` or `obj/merge!`, so they qualify as clean Case-A migrations. frontend/src/app/main/ui/shapes/text/fo_text.cljs (6 components) ---------------------------------------------------------------- - `render-text` -> `render-text*` - `render-root` -> `render-root*` - `render-paragraph-set` -> `render-paragraph-set*` - `render-paragraph` -> `render-paragraph*` - `render-node` -> `render-node*` (forward-props case, see below) - `text-shape` -> `text-shape*` (`::mf/forward-ref` preserved) The four leaf components switch from `[props]` + per-key `(obj/get props "key")` to standard destructuring. `text-shape` already used destructuring under `::mf/props :obj`; that legacy metadata is dropped because the modern `*` form handles props automatically. Its single `::mf/forward-ref true` is kept per the prompt's "preserve forward-ref" rule. `render-node` is the recursive driver. It needs to forward all of its incoming props to the matched paragraph-* / text component and then to a child `render-node*` after overriding `:node`, `:index` and `:key`. The migrated form uses `::mf/props :obj` together with `{:keys [node] :as props}` to keep the JS-object props symbol available, and `(mf/spread-props props {…})` replaces the previous `obj/clone` + `obj/set!` chain. `app.util.object` is no longer required by this namespace and the `(:require ... [app.util.object :as obj] ...)` line is removed. frontend/src/app/main/ui/shapes/text/html_text.cljs (6 components) ----------------------------------------------------------------- Identical six-component shape as `fo_text.cljs`, plus a `code?` flag threaded through every component to switch the rendering path between regular shapes and code-style shapes. - `render-text` -> `render-text*` - `render-root` -> `render-root*` - `render-paragraph-set` -> `render-paragraph-set*` - `render-paragraph` -> `render-paragraph*` - `render-node` -> `render-node*` (same forward-props treatment as above, plus `is-code` in the spread) - `text-shape` -> `text-shape*` (`::mf/forward-ref` preserved) The `code?` boolean prop is renamed to `is-code` per the migration prompt's "?-suffixed boolean -> `is-` prefix" rule. The rename is applied at every read site (5 components) and at the `text-shape*` internal call to `render-node*`, so the prop is consistent inside the namespace. `app.util.object` is no longer required by this namespace either and the corresponding `:require` line is dropped. External call sites (3 files, 4 sites) -------------------------------------- - `frontend/src/app/main/ui/shapes/text.cljs` - the legacy text-shape wrapper (intentionally kept legacy in this PR because it dispatches to `svg/text-shape`, which is still being touched by the in-flight PR penpot#9016) now calls `[:> fo/text-shape* props]`. The `props` symbol is the wrapper's incoming JS-object; modern destructured components accept JS-object props at the call site via `[:>` so this works unchanged. - `frontend/src/app/util/code_gen/markup_html.cljs` - `(mf/element text/text-shape #js {:shape shape :code? true})` becomes `(mf/element text/text-shape* #js {:shape shape :is-code true})` (component renamed and the `code?` JS key updated to match the renamed prop). - `frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs` - `[:& html/text-shape {…}]` -> `[:> html/text-shape* {…}]`. Behavior preserved verbatim --------------------------- Same render output, same forward-ref forwarding semantics, same recursive children-by-index keying, same default `:dir "auto"` on `render-paragraph*`. The visible-prop changes are only the `code?` -> `is-code` rename, all driven from this namespace and its single caller in `markup_html.cljs`. Github penpot#9260 Signed-off-by: FairyPigDev <luislee3108@gmail.com>
1 parent defeeab commit fa06efa

5 files changed

Lines changed: 85 additions & 131 deletions

File tree

frontend/src/app/main/ui/shapes/text.cljs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,4 @@
4343
;; will give a tainted canvas error because the `foreignObject` cannot be
4444
;; rendered.
4545
(and (nil? position-data) (or is-component? is-render?))
46-
[:> fo/text-shape props])))
46+
[:> fo/text-shape* props])))

frontend/src/app/main/ui/shapes/text/fo_text.cljs

Lines changed: 32 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,73 +11,54 @@
1111
[app.common.geom.shapes :as gsh]
1212
[app.common.types.color :as cc]
1313
[app.main.ui.shapes.text.styles :as sts]
14-
[app.util.object :as obj]
1514
[cuerdas.core :as str]
1615
[rumext.v2 :as mf]))
1716

18-
(mf/defc render-text
19-
{::mf/wrap-props false}
20-
[props]
21-
(let [node (obj/get props "node")
22-
parent (obj/get props "parent")
23-
shape (obj/get props "shape")
24-
text (:text node)
25-
style (if (= text "")
26-
(sts/generate-text-styles shape parent)
27-
(sts/generate-text-styles shape node))]
17+
(mf/defc render-text*
18+
[{:keys [node parent shape]}]
19+
(let [text (:text node)
20+
style (if (= text "")
21+
(sts/generate-text-styles shape parent)
22+
(sts/generate-text-styles shape node))]
2823
[:span.text-node {:style style}
2924
(if (= text "") "\u00A0" text)]))
3025

31-
(mf/defc render-root
32-
{::mf/wrap-props false}
33-
[props]
34-
(let [node (obj/get props "node")
35-
children (obj/get props "children")
36-
shape (obj/get props "shape")
37-
style (sts/generate-root-styles shape node)]
26+
(mf/defc render-root*
27+
[{:keys [node children shape]}]
28+
(let [style (sts/generate-root-styles shape node)]
3829
[:div.root.rich-text
3930
{:style style
4031
:xmlns "http://www.w3.org/1999/xhtml"}
4132
children]))
4233

43-
(mf/defc render-paragraph-set
44-
{::mf/wrap-props false}
45-
[props]
46-
(let [children (obj/get props "children")
47-
shape (obj/get props "shape")
48-
style (sts/generate-paragraph-set-styles shape)]
34+
(mf/defc render-paragraph-set*
35+
[{:keys [children shape]}]
36+
(let [style (sts/generate-paragraph-set-styles shape)]
4937
[:div.paragraph-set {:style style} children]))
5038

51-
(mf/defc render-paragraph
52-
{::mf/wrap-props false}
53-
[props]
54-
(let [node (obj/get props "node")
55-
shape (obj/get props "shape")
56-
children (obj/get props "children")
57-
style (sts/generate-paragraph-styles shape node)
58-
dir (:text-direction node "auto")]
39+
(mf/defc render-paragraph*
40+
[{:keys [node children shape]}]
41+
(let [style (sts/generate-paragraph-styles shape node)
42+
dir (:text-direction node "auto")]
5943
[:p.paragraph {:style style :dir dir} children]))
6044

6145
;; -- Text nodes
62-
(mf/defc render-node
63-
{::mf/wrap-props false}
64-
[props]
65-
(let [{:keys [type text children]} (obj/get props "node")]
46+
(mf/defc render-node*
47+
{::mf/props :obj}
48+
[{:keys [node] :as props}]
49+
(let [{:keys [type text children]} node]
6650
(if (string? text)
67-
[:> render-text props]
51+
[:> render-text* props]
6852
(let [component (case type
69-
"root" render-root
70-
"paragraph-set" render-paragraph-set
71-
"paragraph" render-paragraph
53+
"root" render-root*
54+
"paragraph-set" render-paragraph-set*
55+
"paragraph" render-paragraph*
7256
nil)]
7357
(when component
7458
[:> component props
75-
(for [[index node] (d/enumerate children)]
76-
(let [props (-> (obj/clone props)
77-
(obj/set! "node" node)
78-
(obj/set! "index" index)
79-
(obj/set! "key" index))]
80-
[:> render-node props]))])))))
59+
(for [[index child-node] (d/enumerate children)]
60+
[:> render-node*
61+
(mf/spread-props props {:node child-node :index index :key index})])])))))
8162

8263
(defn- next-color
8364
"Given a set of colors try to get a color not yet used"
@@ -168,9 +149,8 @@
168149

169150
[colors color-mapping color-mapping-inverse]))
170151

171-
(mf/defc text-shape
172-
{::mf/props :obj
173-
::mf/forward-ref true}
152+
(mf/defc text-shape*
153+
{::mf/forward-ref true}
174154
[{:keys [shape grow-type]} ref]
175155
(let [transform (gsh/transform-str shape)
176156
id (dm/get-prop shape :id)
@@ -196,6 +176,6 @@
196176
;; `background-clip`
197177
[:style ".text-node { background-clip: text;
198178
-webkit-background-clip: text; }"]
199-
[:& render-node {:index 0
200-
:shape shape
201-
:node content}]]))
179+
[:> render-node* {:index 0
180+
:shape shape
181+
:node content}]]))

frontend/src/app/main/ui/shapes/text/html_text.cljs

Lines changed: 47 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -10,99 +10,73 @@
1010
[app.common.data.macros :as dm]
1111
[app.common.text :as legacy.txt]
1212
[app.main.ui.shapes.text.styles :as sts]
13-
[app.util.object :as obj]
1413
[rumext.v2 :as mf]))
1514

16-
(mf/defc render-text
17-
{::mf/wrap-props false}
18-
[props]
19-
(let [node (obj/get props "node")
20-
parent (obj/get props "parent")
21-
shape (obj/get props "shape")
22-
code? (obj/get props "code?")
23-
text (:text node)
24-
style (if (= text "")
25-
(sts/generate-text-styles shape parent)
26-
(sts/generate-text-styles shape node))
27-
class (when code? (:$id node))]
15+
(mf/defc render-text*
16+
[{:keys [node parent shape is-code]}]
17+
(let [text (:text node)
18+
style (if (= text "")
19+
(sts/generate-text-styles shape parent)
20+
(sts/generate-text-styles shape node))
21+
class (when is-code (:$id node))]
2822
[:span.text-node {:style style :class class}
2923
(if (= text "") "\u00A0" text)]))
3024

31-
(mf/defc render-root
32-
{::mf/wrap-props false}
33-
[props]
34-
(let [node (obj/get props "node")
35-
children (obj/get props "children")
36-
shape (obj/get props "shape")
37-
code? (obj/get props "code?")
38-
style (sts/generate-root-styles shape node code?)
39-
class (when code? (:$id node))]
25+
(mf/defc render-root*
26+
[{:keys [node children shape is-code]}]
27+
(let [style (sts/generate-root-styles shape node is-code)
28+
class (when is-code (:$id node))]
4029
[:div.root.rich-text
4130
{:style style
4231
:class class
4332
:xmlns "http://www.w3.org/1999/xhtml"}
4433
children]))
4534

46-
(mf/defc render-paragraph-set
47-
{::mf/wrap-props false}
48-
[props]
49-
(let [node (obj/get props "node")
50-
children (obj/get props "children")
51-
shape (obj/get props "shape")
52-
code? (obj/get props "code?")
53-
style (when-not code? (sts/generate-paragraph-set-styles shape))
54-
class (when code? (:$id node))]
35+
(mf/defc render-paragraph-set*
36+
[{:keys [node children shape is-code]}]
37+
(let [style (when-not is-code (sts/generate-paragraph-set-styles shape))
38+
class (when is-code (:$id node))]
5539
[:div.paragraph-set {:style style :class class} children]))
5640

57-
(mf/defc render-paragraph
58-
{::mf/wrap-props false}
59-
[props]
60-
(let [node (obj/get props "node")
61-
shape (obj/get props "shape")
62-
children (obj/get props "children")
63-
code? (obj/get props "code?")
64-
style (when-not code? (sts/generate-paragraph-styles shape node))
65-
class (when code? (:$id node))
66-
dir (:text-direction node "auto")]
41+
(mf/defc render-paragraph*
42+
[{:keys [node children shape is-code]}]
43+
(let [style (when-not is-code (sts/generate-paragraph-styles shape node))
44+
class (when is-code (:$id node))
45+
dir (:text-direction node "auto")]
6746
[:p.paragraph {:style style :dir dir :class class} children]))
6847

6948
;; -- Text nodes
70-
(mf/defc render-node
71-
{::mf/wrap-props false}
72-
[props]
73-
(let [{:keys [type text children] :as parent} (obj/get props "node")
74-
code? (obj/get props "code?")]
49+
(mf/defc render-node*
50+
{::mf/props :obj}
51+
[{:keys [node is-code] :as props}]
52+
(let [{:keys [type text children] :as parent} node]
7553
(if (string? text)
76-
[:> render-text props]
54+
[:> render-text* props]
7755
(let [component (case type
78-
"root" render-root
79-
"paragraph-set" render-paragraph-set
80-
"paragraph" render-paragraph
56+
"root" render-root*
57+
"paragraph-set" render-paragraph-set*
58+
"paragraph" render-paragraph*
8159
nil)]
8260
(when component
8361
[:> component props
84-
(for [[index node] (d/enumerate children)]
85-
(let [props (-> (obj/clone props)
86-
(obj/set! "node" node)
87-
(obj/set! "parent" parent)
88-
(obj/set! "index" index)
89-
(obj/set! "key" index)
90-
(obj/set! "code?" code?))]
91-
[:> render-node props]))])))))
62+
(for [[index child-node] (d/enumerate children)]
63+
[:> render-node*
64+
(mf/spread-props props
65+
{:node child-node
66+
:parent parent
67+
:index index
68+
:key index
69+
:is-code is-code})])])))))
9270

93-
(mf/defc text-shape
94-
{::mf/wrap-props false
95-
::mf/forward-ref true}
96-
[props ref]
97-
(let [shape (obj/get props "shape")
98-
grow-type (obj/get props "grow-type")
99-
code? (obj/get props "code?")
100-
{:keys [id x y width height content]} shape
71+
(mf/defc text-shape*
72+
{::mf/forward-ref true}
73+
[{:keys [shape grow-type is-code]} ref]
74+
(let [{:keys [id x y width height content]} shape
10175

102-
content (if code? (legacy.txt/index-content content) content)
76+
content (if is-code (legacy.txt/index-content content) content)
10377

10478
style
105-
(when-not code?
79+
(when-not is-code
10680
#js {:position "fixed"
10781
:left 0
10882
:top 0
@@ -118,10 +92,10 @@
11892
:style style}
11993
;; We use a class here because react has a bug that won't use the appropriate selector for
12094
;; `background-clip`
121-
(when (not code?)
95+
(when (not is-code)
12296
[:style ".text-node { background-clip: text;
12397
-webkit-background-clip: text; }"])
124-
[:& render-node {:index 0
125-
:shape shape
126-
:node content
127-
:code? code?}]]))
98+
[:> render-node* {:index 0
99+
:shape shape
100+
:node content
101+
:is-code is-code}]]))

frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,10 @@
130130
(when (some? node)
131131
(on-update shape node))))]
132132

133-
[:& html/text-shape {:key (str "shape-" (:id shape))
134-
:ref handle-update
135-
:shape shape
136-
:grow-type (:grow-type shape)}]))
133+
[:> html/text-shape* {:key (str "shape-" (:id shape))
134+
:ref handle-update
135+
:shape shape
136+
:grow-type (:grow-type shape)}]))
137137

138138
(defn text-properties-equal?
139139
[shape other]

frontend/src/app/util/code_gen/markup_html.cljs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
indent))
3939

4040
(cfh/text-shape? shape)
41-
(let [text-shape-html (rds/renderToStaticMarkup (mf/element text/text-shape #js {:shape shape :code? true}))
41+
(let [text-shape-html (rds/renderToStaticMarkup (mf/element text/text-shape* #js {:shape shape :is-code true}))
4242
text-shape-html (str/replace text-shape-html #"style\s*=\s*[\"'][^\"']*[\"']" "")]
4343
(dm/fmt "%<div class=\"%\">\n%\n%</div>"
4444
indent

0 commit comments

Comments
 (0)