mirror of
https://github.com/penpot/penpot.git
synced 2026-04-25 11:18:36 +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
|
||||
"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."
|
||||
[tokens]
|
||||
(reduce
|
||||
(fn [acc [_ token]]
|
||||
(let [temp-id (random-uuid)
|
||||
token (assoc token :temp/id temp-id)
|
||||
path (get-token-path token)]
|
||||
(let [path (get-token-path token)]
|
||||
(-> acc
|
||||
(assoc-in (concat [:tokens-tree] path) token)
|
||||
(assoc-in [:ids temp-id] token))))
|
||||
(assoc-in [:ids (:id token)] token))))
|
||||
{:tokens-tree {} :ids {}}
|
||||
tokens))
|
||||
|
||||
|
||||
@ -551,7 +551,7 @@
|
||||
(.. sd-token -original -name))
|
||||
|
||||
(defn sd-token-uuid [^js sd-token]
|
||||
(uuid (.-uuid (.-id ^js sd-token))))
|
||||
(uuid (.-uuid (.. sd-token -original -id))))
|
||||
|
||||
(defn resolve-tokens
|
||||
[tokens]
|
||||
@ -560,15 +560,23 @@
|
||||
|
||||
(defn resolve-tokens-interactive
|
||||
"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
|
||||
so we know if references are missing / to resolve them and possibly show interactive previews (in the tokens form) to the user.
|
||||
We have to pass in all tokens from all sets in the entire library to
|
||||
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,
|
||||
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."
|
||||
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, 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]
|
||||
(let [{:keys [tokens-tree ids]} (ctob/backtrace-tokens-tree tokens)]
|
||||
(resolve-tokens-tree tokens-tree #(get ids (sd-token-uuid %)))))
|
||||
@ -584,10 +592,11 @@
|
||||
(defonce !tokens-cache (atom nil))
|
||||
|
||||
(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,
|
||||
then the state will be updated with the resolved tokens."
|
||||
This hook will return the unresolved tokens as state until they are
|
||||
processed, then the state will be updated with the resolved tokens."
|
||||
[tokens & {:keys [cache-atom interactive?]
|
||||
:or {cache-atom !tokens-cache}
|
||||
:as config}]
|
||||
|
||||
@ -57,3 +57,29 @@
|
||||
(t/is (= :error.token/number-too-large
|
||||
(get-in resolved-tokens ["borderRadius.largeFn" :errors 0 :error/code])))
|
||||
(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