mirror of
https://github.com/penpot/penpot.git
synced 2026-09-11 22:49:30 +00:00
🐛 Fix fontFamilies token property mapping in Plugin API (#11566)
* 🐛 Fix fontFamilies token property mapping in Plugin API The Plugin API exposes the font-family token property as `fontFamilies`, while Penpot stores the canonical applied-token attribute as `:font-family`. The bidirectional plugin/internal attribute map did not contain that alias, so explicit `applyToken(..., ["fontFamilies"])` validation rejected the property and applied-token readback exposed the undocumented singular `fontFamily`. Add `:font-family -> :font-families` to the existing canonical alias map. The reverse mapping is derived automatically, keeping application and readback symmetric without introducing a font-specific code path. Closes #11405 AI-assisted-by: Omen Alpha Signed-off-by: 최준수 <junsoo1172@gmail.com> * 🐛 Fix fontFamilies e2e test to target a text shape The fontFamilies end-to-end regression created a flex layout frame, whose attribute set (frame-with-layout-attributes) excludes :font-family. The workspace token application filters such shapes, so the internal binding and readback assertions would pass vacuously without exercising the alias. Target an actual `:text` shape (ctho/add-text) instead, so the test verifies the full JS "fontFamilies" -> schema -> alias -> canonical :font-family -> camelCase readback path. AI-assisted-by: Omen Alpha Signed-off-by: 최준수 <junsoo1172@gmail.com> * 🐛 Fix fontFamilies test WASM error and add changelog entry The text-shape fontFamilies e2e applies a layout-affecting token via wasm renderer path, hitting missing WASM exports under Node. Merge thw/setup-wasm-mocks! into the :each fixture and add plugins CHANGELOG entry for the fontFamilies alias fix. AI-assisted-by: muse-spark-1.3-contributor Related to #11566 Signed-off-by: makesomethingshit <junsoo1172@gmail.com> --------- Signed-off-by: 최준수 <junsoo1172@gmail.com> Signed-off-by: makesomethingshit <junsoo1172@gmail.com>
This commit is contained in:
parent
dc12f1db91
commit
30849babcc
@ -41,7 +41,9 @@
|
|||||||
:m1 :margin-top
|
:m1 :margin-top
|
||||||
:m2 :margin-right
|
:m2 :margin-right
|
||||||
:m3 :margin-bottom
|
:m3 :margin-bottom
|
||||||
:m4 :margin-left})
|
:m4 :margin-left
|
||||||
|
|
||||||
|
:font-family :font-families})
|
||||||
|
|
||||||
(def ^:private map:token-attr-plugin->token-attr
|
(def ^:private map:token-attr-plugin->token-attr
|
||||||
(merge
|
(merge
|
||||||
|
|||||||
@ -22,9 +22,14 @@
|
|||||||
[cljs.test :as t :include-macros true]
|
[cljs.test :as t :include-macros true]
|
||||||
[frontend-tests.helpers.mock :as mock]
|
[frontend-tests.helpers.mock :as mock]
|
||||||
[frontend-tests.helpers.state :as ths]
|
[frontend-tests.helpers.state :as ths]
|
||||||
|
[frontend-tests.helpers.wasm :as thw]
|
||||||
[potok.v2.core :as ptk]))
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
(t/use-fixtures :each {:before cthi/reset-idmap!})
|
(t/use-fixtures :each
|
||||||
|
{:before (fn []
|
||||||
|
(cthi/reset-idmap!)
|
||||||
|
(thw/setup-wasm-mocks!))
|
||||||
|
:after thw/teardown-wasm-mocks!})
|
||||||
|
|
||||||
(def ^:private get-resolved-value @#'ptok/get-resolved-value)
|
(def ^:private get-resolved-value @#'ptok/get-resolved-value)
|
||||||
|
|
||||||
@ -81,6 +86,18 @@
|
|||||||
(t/is (= :m3 (ptok/token-attr-plugin->token-attr :margin-bottom)))
|
(t/is (= :m3 (ptok/token-attr-plugin->token-attr :margin-bottom)))
|
||||||
(t/is (= :m4 (ptok/token-attr-plugin->token-attr :margin-left))))
|
(t/is (= :m4 (ptok/token-attr-plugin->token-attr :margin-left))))
|
||||||
|
|
||||||
|
(t/deftest token-attr-plugin->token-attr-resolves-font-family-alias
|
||||||
|
;; Plugin-facing `fontFamilies` (kebab-cased to `:font-families` by the
|
||||||
|
;; schema layer) maps to the canonical internal `:font-family`.
|
||||||
|
(t/is (= :font-family (ptok/token-attr-plugin->token-attr :font-families)))
|
||||||
|
(t/is (= :font-family (ptok/token-attr-plugin->token-attr "font-families"))))
|
||||||
|
|
||||||
|
(t/deftest token-attr->token-attr-plugin-resolves-font-family-alias
|
||||||
|
;; Symmetric direction: the canonical internal attribute maps to the
|
||||||
|
;; plural plugin-facing name so applied-token readback serializes as
|
||||||
|
;; camelCase `fontFamilies`, not the undocumented singular `fontFamily`.
|
||||||
|
(t/is (= :font-families (ptok/token-attr->token-attr-plugin :font-family))))
|
||||||
|
|
||||||
(t/deftest token-attr-plugin->token-attr-coerces-string-input
|
(t/deftest token-attr-plugin->token-attr-coerces-string-input
|
||||||
;; This is the actual regression — JS plugin calls supply strings.
|
;; This is the actual regression — JS plugin calls supply strings.
|
||||||
(t/is (= :fill (ptok/token-attr-plugin->token-attr "fill")))
|
(t/is (= :fill (ptok/token-attr-plugin->token-attr "fill")))
|
||||||
@ -150,6 +167,57 @@
|
|||||||
(done)))
|
(done)))
|
||||||
0))))
|
0))))
|
||||||
|
|
||||||
|
(t/deftest shape-apply-token-accepts-font-families
|
||||||
|
(t/async
|
||||||
|
done
|
||||||
|
(let [set-id (cthi/new-id! :token-set)
|
||||||
|
token-id (cthi/new-id! :font-family-token)
|
||||||
|
file (-> (cthf/sample-file :file1 :page-label :page1)
|
||||||
|
(ctho/add-text :text1 "Hello World!")
|
||||||
|
(ctht/add-tokens-lib)
|
||||||
|
(ctht/update-tokens-lib
|
||||||
|
#(-> %
|
||||||
|
(ctob/add-set
|
||||||
|
(ctob/make-token-set :id set-id
|
||||||
|
:name "fonts"))
|
||||||
|
(ctob/add-theme
|
||||||
|
(ctob/make-token-theme :name "theme"
|
||||||
|
:sets #{"fonts"}))
|
||||||
|
(ctob/set-active-themes #{"/theme"})
|
||||||
|
(ctob/add-token
|
||||||
|
set-id
|
||||||
|
(ctob/make-token :id token-id
|
||||||
|
:name "font.primary"
|
||||||
|
:type :font-family
|
||||||
|
:value ["Inter"])))))
|
||||||
|
store (ths/setup-store file)
|
||||||
|
_ (set! st/state store)
|
||||||
|
_ (set! st/stream (ptk/input-stream store))
|
||||||
|
^js context (api/create-context "00000000-0000-0000-0000-000000000000")
|
||||||
|
^js page (.-currentPage context)
|
||||||
|
^js shape (.getShapeById page (str (cthi/id :text1)))
|
||||||
|
^js library (.-library context)
|
||||||
|
^js local (.-local library)
|
||||||
|
^js catalog (.-tokens local)
|
||||||
|
^js token-set (.getSetById catalog (str set-id))
|
||||||
|
^js token (.getTokenById token-set (str token-id))]
|
||||||
|
(.applyToken shape token #js ["fontFamilies"])
|
||||||
|
(js/setTimeout
|
||||||
|
(fn []
|
||||||
|
(let [shape-id (cthi/id :text1)
|
||||||
|
page-id (cthf/current-page-id file)]
|
||||||
|
;; Plugin readback exposes the documented plural key.
|
||||||
|
(t/is (= "font.primary" (.. shape -tokens -fontFamilies)))
|
||||||
|
;; The undocumented singular spelling must not leak.
|
||||||
|
(t/is (undefined? (.. shape -tokens -fontFamily)))
|
||||||
|
;; Internal state keeps the canonical `:font-family` key.
|
||||||
|
(t/is (= "font.primary"
|
||||||
|
(get-in @store
|
||||||
|
[:files (:id file) :data :pages-index page-id
|
||||||
|
:objects shape-id :applied-tokens :font-family])))
|
||||||
|
(done)))
|
||||||
|
0))))
|
||||||
|
|
||||||
(t/deftest token-attr?-rejects-unknown-input
|
(t/deftest token-attr?-rejects-unknown-input
|
||||||
(t/is (false? (boolean (ptok/token-attr? :not-a-real-attr))))
|
(t/is (false? (boolean (ptok/token-attr? :not-a-real-attr))))
|
||||||
(t/is (false? (boolean (ptok/token-attr? "not-a-real-attr"))))
|
(t/is (false? (boolean (ptok/token-attr? "not-a-real-attr"))))
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
- **plugins-runtime**: `Library.createComponent()` now rejects invalid input (an empty shape list, or a shape inside a component copy) with a validation error instead of returning a component proxy pointing at nothing.
|
- **plugins-runtime**: `Library.createComponent()` now rejects invalid input (an empty shape list, or a shape inside a component copy) with a validation error instead of returning a component proxy pointing at nothing.
|
||||||
- **plugins-runtime**: Setting an individual padding/margin side (`leftPadding`, `topMargin`, …) now re-derives the padding/margin type, switching to `multiple` when the four sides stop being symmetric (so the value is actually painted) and back to `simple` once top/bottom and left/right are mirrored again.
|
- **plugins-runtime**: Setting an individual padding/margin side (`leftPadding`, `topMargin`, …) now re-derives the padding/margin type, switching to `multiple` when the four sides stop being symmetric (so the value is actually painted) and back to `simple` once top/bottom and left/right are mirrored again.
|
||||||
- **plugins-runtime**: Removed the premature deep-hardening of the host plugin context, which froze shared host functions (including `Function.prototype`) before SES override taming, causing `TypeError: Cannot assign to read only property 'toString'` on later host-side function extension. Related to #11001.
|
- **plugins-runtime**: Removed the premature deep-hardening of the host plugin context, which froze shared host functions (including `Function.prototype`) before SES override taming, causing `TypeError: Cannot assign to read only property 'toString'` on later host-side function extension. Related to #11001.
|
||||||
|
- **plugins-runtime**: Fixed the `fontFamilies` token property mapping so `Shape.applyToken(token, ["fontFamilies"])` resolves to the canonical `:font-family` attribute and applied-token readback exposes the documented `fontFamilies` key instead of the undocumented singular `fontFamily`. Closes #11405.
|
||||||
|
|
||||||
## 1.5.0 (2026-07-08)
|
## 1.5.0 (2026-07-08)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user