mirror of
https://github.com/penpot/penpot.git
synced 2026-07-03 21:05:25 +00:00
🐛 Plugin API theme.addSet/removeSet accept proxy or set ID
Signed-off-by: RenzoMXD <170978465+RenzoMXD@users.noreply.github.com>
🐛 Preserve validation errors for theme set APIs
Signed-off-by: RenzoMXD <170978465+RenzoMXD@users.noreply.github.com>
Co-authored-by: Alonso Torres <alonso.torres@kaleidos.net>
This commit is contained in:
parent
5b7447fbe4
commit
1c9ab691e6
@ -453,6 +453,23 @@
|
||||
(defn token-theme-proxy? [p]
|
||||
(obj/type-of? p "TokenThemeProxy"))
|
||||
|
||||
(defn- resolve-token-set
|
||||
"Resolves an addSet/removeSet argument to a token set. A proxy is returned
|
||||
as-is; an id is located in the file's token library."
|
||||
[file-id set-arg]
|
||||
(if (token-set-proxy? set-arg)
|
||||
set-arg
|
||||
(u/locate-token-set file-id set-arg)))
|
||||
|
||||
(defn- token-set-name
|
||||
"Reads the name from a resolved token set, supporting both proxies (whose
|
||||
getter falls back to the freshly-created name) and located sets."
|
||||
[set]
|
||||
(when (some? set)
|
||||
(if (token-set-proxy? set)
|
||||
(obj/get set "name")
|
||||
(ctob/get-name set))))
|
||||
|
||||
(defn token-theme-proxy
|
||||
[plugin-id file-id id]
|
||||
(obj/reify {:name "TokenThemeProxy"
|
||||
@ -535,27 +552,20 @@
|
||||
|
||||
:addSet
|
||||
{:enumerable false
|
||||
:schema [:tuple [:fn token-set-proxy?]]
|
||||
:fn (fn [token-set]
|
||||
;; Resolve the set name before the theme lookup. The proxy's :name
|
||||
;; getter now falls back to `initial-name` when state hasn't
|
||||
;; propagated, so this is safe even for freshly created sets.
|
||||
;; Guard against nil to prevent `enable-set` from conj'ing nil
|
||||
;; into the theme's :sets — which would send `:sets #{nil}` to the
|
||||
;; backend and crash the workspace.
|
||||
(let [set-name (obj/get token-set "name")
|
||||
:schema [:tuple [:or [:fn token-set-proxy?] ::sm/uuid]]
|
||||
:fn (fn [set-arg]
|
||||
(let [set-name (token-set-name (resolve-token-set file-id set-arg))
|
||||
theme (u/locate-token-theme file-id id)]
|
||||
(when (and (some? set-name) (some? theme))
|
||||
(when (and set-name theme)
|
||||
(st/emit! (dwtl/update-token-theme id (ctob/enable-set theme set-name))))))}
|
||||
|
||||
:removeSet
|
||||
{:enumerable false
|
||||
:schema [:tuple [:fn token-set-proxy?]]
|
||||
:fn (fn [token-set]
|
||||
;; Same nil guard as addSet — see comment above.
|
||||
(let [set-name (obj/get token-set "name")
|
||||
:schema [:tuple [:or [:fn token-set-proxy?] ::sm/uuid]]
|
||||
:fn (fn [set-arg]
|
||||
(let [set-name (token-set-name (resolve-token-set file-id set-arg))
|
||||
theme (u/locate-token-theme file-id id)]
|
||||
(when (and (some? set-name) (some? theme))
|
||||
(when (and set-name theme)
|
||||
(st/emit! (dwtl/update-token-theme id (ctob/disable-set theme set-name))))))}
|
||||
|
||||
:duplicate
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
[app.common.test-helpers.ids-map :as cthi]
|
||||
[app.common.test-helpers.tokens :as ctht]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.tokenscript :as ts]
|
||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||
[app.main.store :as st]
|
||||
@ -338,3 +339,66 @@
|
||||
result (get-resolved-value token {(:name token) token})]
|
||||
(t/is (array? result))
|
||||
(t/is (= ["Inter" "Arial"] (vec result)))))
|
||||
|
||||
(t/deftest token-theme-add-set-accepts-token-set-id
|
||||
(let [plugin-id "plugin-id"
|
||||
file-id (uuid/next)
|
||||
theme-id (uuid/next)
|
||||
set-id (uuid/next)
|
||||
token-set (ctob/make-token-set :id set-id :name "Core")
|
||||
theme (ctob/make-token-theme :id theme-id :group "mode" :name "Light")
|
||||
emitted (atom [])
|
||||
invalid (atom [])]
|
||||
(with-redefs [u/locate-token-set (fn [_ id] (when (= id set-id) token-set))
|
||||
u/locate-token-theme (fn [_ id] (when (= id theme-id) theme))
|
||||
u/not-valid (fn [_ code value] (swap! invalid conj [code value]))
|
||||
dwtl/update-token-theme (fn [id theme] {:id id :theme theme})
|
||||
st/emit! (fn ([event] (swap! emitted conj event) nil)
|
||||
([event & _] (swap! emitted conj event) nil))]
|
||||
(let [theme-proxy (ptok/token-theme-proxy plugin-id file-id theme-id)]
|
||||
(.addSet theme-proxy (str set-id))
|
||||
(t/is (= #{"Core"} (-> @emitted first :theme :sets)))
|
||||
(t/is (empty? @invalid))))))
|
||||
|
||||
(t/deftest token-theme-add-set-accepts-token-set-proxy
|
||||
(let [plugin-id "plugin-id"
|
||||
file-id (uuid/next)
|
||||
theme-id (uuid/next)
|
||||
set-id (uuid/next)
|
||||
token-set (ctob/make-token-set :id set-id :name "Core")
|
||||
theme (ctob/make-token-theme :id theme-id :group "mode" :name "Light")
|
||||
emitted (atom [])
|
||||
invalid (atom [])]
|
||||
(with-redefs [u/locate-token-set (fn [_ id] (when (= id set-id) token-set))
|
||||
u/locate-token-theme (fn [_ id] (when (= id theme-id) theme))
|
||||
u/not-valid (fn [_ code value] (swap! invalid conj [code value]))
|
||||
dwtl/update-token-theme (fn [id theme] {:id id :theme theme})
|
||||
st/emit! (fn ([event] (swap! emitted conj event) nil)
|
||||
([event & _] (swap! emitted conj event) nil))]
|
||||
(let [theme-proxy (ptok/token-theme-proxy plugin-id file-id theme-id)
|
||||
set-proxy (ptok/token-set-proxy plugin-id file-id set-id "Core")]
|
||||
(.addSet theme-proxy set-proxy)
|
||||
(t/is (= #{"Core"} (-> @emitted first :theme :sets)))
|
||||
(t/is (empty? @invalid))))))
|
||||
|
||||
(t/deftest token-theme-add-set-rejects-invalid-arguments
|
||||
(let [plugin-id "plugin-id"
|
||||
file-id (uuid/next)
|
||||
theme-id (uuid/next)
|
||||
theme (ctob/make-token-theme :id theme-id :group "mode" :name "Light")
|
||||
emitted (atom [])
|
||||
invalid (atom [])]
|
||||
(with-redefs [u/locate-token-set (constantly nil)
|
||||
u/locate-token-theme (fn [_ id] (when (= id theme-id) theme))
|
||||
u/not-valid (fn [_ code value] (swap! invalid conj [code value]))
|
||||
dwtl/update-token-theme (fn [id theme] {:id id :theme theme})
|
||||
st/emit! (fn ([event] (swap! emitted conj event) nil)
|
||||
([event & _] (swap! emitted conj event) nil))]
|
||||
(let [theme-proxy (ptok/token-theme-proxy plugin-id file-id theme-id)]
|
||||
;; Non-id, non-proxy arguments are rejected by the schema coercer.
|
||||
(.addSet theme-proxy 42)
|
||||
(.removeSet theme-proxy nil)
|
||||
(t/is (empty? @emitted))
|
||||
(t/is (= 2 (count @invalid)))
|
||||
(t/is (every? #(= :error (first %)) @invalid))))))
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
- **plugin-types**: Added `fixedWhenScrolling` property for shapes
|
||||
- **plugin-runtime:** `addToken` now resolves references against all token sets, allowing references to tokens in inactive sets
|
||||
- **plugin-types:** `TokenCatalog.addSet` now accepts an optional `active` flag to create an already-active set (sets are inactive by default)
|
||||
- **plugin-types:** `TokenTheme.addSet` and `TokenTheme.removeSet` now accept a token set id (`string`) in addition to a `TokenSet`
|
||||
- **plugin-runtime:** A `fontFamilies` token's `resolvedValue` now returns the documented `string[]` (the resolved family list) instead of leaking the raw tokenscript list symbol
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
8
plugins/libs/plugin-types/index.d.ts
vendored
8
plugins/libs/plugin-types/index.d.ts
vendored
@ -5291,13 +5291,17 @@ export interface TokenTheme {
|
||||
|
||||
/**
|
||||
* Adds a set to the list of the theme.
|
||||
*
|
||||
* @param tokenSet a `TokenSet` or the id of a token set.
|
||||
*/
|
||||
addSet(tokenSet: TokenSet): void;
|
||||
addSet(tokenSet: TokenSet | string): void;
|
||||
|
||||
/**
|
||||
* Removes a set from the list of the theme.
|
||||
*
|
||||
* @param tokenSet a `TokenSet` or the id of a token set.
|
||||
*/
|
||||
removeSet(tokenSet: TokenSet): void;
|
||||
removeSet(tokenSet: TokenSet | string): void;
|
||||
|
||||
/**
|
||||
* Adds to the catalog a new TokenTheme equal to this one but with a new id.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user