mirror of
https://github.com/penpot/penpot.git
synced 2026-07-28 00:48:22 +00:00
🐛 Fix TypeError in sd-token-uuid when resolving tokens interactively (#8929)
The backtrace-tokens-tree function used a namespaced keyword :temp/id which clj->js converted to the JS property "temp/id". The sd-token-uuid function then tried to access .id on the sd-token top-level object, which was undefined, causing "Cannot read properties of undefined (reading uuid)". Fix by using the existing token :id instead of generating a temporary one, and read it from sd-token.original (matching sd-token-name pattern).
This commit is contained in:
parent
ef6eeb5693
commit
a403175d5c
@ -485,17 +485,15 @@
|
|||||||
|
|
||||||
(defn backtrace-tokens-tree
|
(defn backtrace-tokens-tree
|
||||||
"Convert tokens into a nested tree with their name as the path.
|
"Convert tokens into a nested tree with their name as the path.
|
||||||
Generates a uuid per token to backtrace a token from an external source (StyleDictionary).
|
Uses the existing token :id to backtrace a token from an external source (StyleDictionary).
|
||||||
The backtrace can't be the name as the name might not exist when the user is creating a token."
|
The backtrace can't be the name as the name might not exist when the user is creating a token."
|
||||||
[tokens]
|
[tokens]
|
||||||
(reduce
|
(reduce
|
||||||
(fn [acc [_ token]]
|
(fn [acc [_ token]]
|
||||||
(let [temp-id (random-uuid)
|
(let [path (get-token-path token)]
|
||||||
token (assoc token :temp/id temp-id)
|
|
||||||
path (get-token-path token)]
|
|
||||||
(-> acc
|
(-> acc
|
||||||
(assoc-in (concat [:tokens-tree] path) token)
|
(assoc-in (concat [:tokens-tree] path) token)
|
||||||
(assoc-in [:ids temp-id] token))))
|
(assoc-in [:ids (:id token)] token))))
|
||||||
{:tokens-tree {} :ids {}}
|
{:tokens-tree {} :ids {}}
|
||||||
tokens))
|
tokens))
|
||||||
|
|
||||||
|
|||||||
@ -551,7 +551,7 @@
|
|||||||
(.. sd-token -original -name))
|
(.. sd-token -original -name))
|
||||||
|
|
||||||
(defn sd-token-uuid [^js sd-token]
|
(defn sd-token-uuid [^js sd-token]
|
||||||
(uuid (.-uuid (.-id ^js sd-token))))
|
(uuid (.-uuid (.. sd-token -original -id))))
|
||||||
|
|
||||||
(defn resolve-tokens
|
(defn resolve-tokens
|
||||||
[tokens]
|
[tokens]
|
||||||
@ -560,15 +560,23 @@
|
|||||||
|
|
||||||
(defn resolve-tokens-interactive
|
(defn resolve-tokens-interactive
|
||||||
"Interactive check of resolving tokens.
|
"Interactive check of resolving tokens.
|
||||||
Uses a ids map to backtrace the original token from the resolved StyleDictionary token.
|
Uses a ids map to backtrace the original token from the resolved
|
||||||
|
StyleDictionary token.
|
||||||
|
|
||||||
We have to pass in all tokens from all sets in the entire library to style dictionary
|
We have to pass in all tokens from all sets in the entire library to
|
||||||
so we know if references are missing / to resolve them and possibly show interactive previews (in the tokens form) to the user.
|
style dictionary so we know if references are missing / to resolve
|
||||||
|
them and possibly show interactive previews (in the tokens form) to
|
||||||
|
the user.
|
||||||
|
|
||||||
Since we're using the :name path as the identifier we might be throwing away or overriding tokens in the tree that we pass to StyleDictionary.
|
Since we're using the :name path as the identifier we might be
|
||||||
|
throwing away or overriding tokens in the tree that we pass to
|
||||||
|
StyleDictionary.
|
||||||
|
|
||||||
So to get back the original token from the resolved sd-token (see my updates for what an sd-token is) we include a temporary :id for the token that we pass to StyleDictionary,
|
So to get back the original token from the resolved sd-token (see my
|
||||||
this way after the resolving computation we can restore any token, even clashing ones with the same :name path by just looking up that :id in the ids map."
|
updates for what an sd-token is) we include a temporary :id for the
|
||||||
|
token that we pass to StyleDictionary, this way after the resolving
|
||||||
|
computation we can restore any token, even clashing ones with the
|
||||||
|
same :name path by just looking up that :id in the ids map."
|
||||||
[tokens]
|
[tokens]
|
||||||
(let [{:keys [tokens-tree ids]} (ctob/backtrace-tokens-tree tokens)]
|
(let [{:keys [tokens-tree ids]} (ctob/backtrace-tokens-tree tokens)]
|
||||||
(resolve-tokens-tree tokens-tree #(get ids (sd-token-uuid %)))))
|
(resolve-tokens-tree tokens-tree #(get ids (sd-token-uuid %)))))
|
||||||
@ -584,10 +592,11 @@
|
|||||||
(defonce !tokens-cache (atom nil))
|
(defonce !tokens-cache (atom nil))
|
||||||
|
|
||||||
(defn use-resolved-tokens
|
(defn use-resolved-tokens
|
||||||
"The StyleDictionary process function is async, so we can't use resolved values directly.
|
"The StyleDictionary process function is async, so we can't use
|
||||||
|
resolved values directly.
|
||||||
|
|
||||||
This hook will return the unresolved tokens as state until they are processed,
|
This hook will return the unresolved tokens as state until they are
|
||||||
then the state will be updated with the resolved tokens."
|
processed, then the state will be updated with the resolved tokens."
|
||||||
[tokens & {:keys [cache-atom interactive?]
|
[tokens & {:keys [cache-atom interactive?]
|
||||||
:or {cache-atom !tokens-cache}
|
:or {cache-atom !tokens-cache}
|
||||||
:as config}]
|
:as config}]
|
||||||
|
|||||||
@ -57,3 +57,29 @@
|
|||||||
(t/is (= :error.token/number-too-large
|
(t/is (= :error.token/number-too-large
|
||||||
(get-in resolved-tokens ["borderRadius.largeFn" :errors 0 :error/code])))
|
(get-in resolved-tokens ["borderRadius.largeFn" :errors 0 :error/code])))
|
||||||
(done))))))))
|
(done))))))))
|
||||||
|
|
||||||
|
(t/deftest resolve-tokens-interactive-test
|
||||||
|
(t/async
|
||||||
|
done
|
||||||
|
(t/testing "resolves tokens interactively using backtrace ids map"
|
||||||
|
(let [tokens (-> (ctob/make-tokens-lib)
|
||||||
|
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :core-set)
|
||||||
|
:name "core"))
|
||||||
|
(ctob/add-token (cthi/id :core-set)
|
||||||
|
(ctob/make-token {:name "borderRadius.sm"
|
||||||
|
:value "12px"
|
||||||
|
:type :border-radius}))
|
||||||
|
(ctob/add-token (cthi/id :core-set)
|
||||||
|
(ctob/make-token {:value "{borderRadius.sm} * 2"
|
||||||
|
:name "borderRadius.md"
|
||||||
|
:type :border-radius}))
|
||||||
|
(ctob/get-all-tokens-map))]
|
||||||
|
(-> (sd/resolve-tokens-interactive tokens)
|
||||||
|
(rx/sub!
|
||||||
|
(fn [resolved-tokens]
|
||||||
|
(t/is (= 12 (get-in resolved-tokens ["borderRadius.sm" :resolved-value])))
|
||||||
|
(t/is (= "px" (get-in resolved-tokens ["borderRadius.sm" :unit])))
|
||||||
|
(t/is (= 24 (get-in resolved-tokens ["borderRadius.md" :resolved-value])))
|
||||||
|
(t/is (= "px" (get-in resolved-tokens ["borderRadius.md" :unit])))
|
||||||
|
(done))))))))
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user