mirror of
https://github.com/penpot/penpot.git
synced 2026-06-02 05:30:19 +00:00
🐛 Keep colliding tokens visible as broken pills
This commit is contained in:
parent
429103d076
commit
0efebc5e0e
@ -138,6 +138,7 @@
|
|||||||
- Fix standalone tokens ordering separated from token groups [#9733](https://github.com/penpot/penpot/issues/9733) (PR: [#9736](https://github.com/penpot/penpot/pull/9736))
|
- Fix standalone tokens ordering separated from token groups [#9733](https://github.com/penpot/penpot/issues/9733) (PR: [#9736](https://github.com/penpot/penpot/pull/9736))
|
||||||
- Fix delete invitation modal readability in light theme [#9737](https://github.com/penpot/penpot/issues/9737) (PR: [#9747](https://github.com/penpot/penpot/pull/9747))
|
- Fix delete invitation modal readability in light theme [#9737](https://github.com/penpot/penpot/issues/9737) (PR: [#9747](https://github.com/penpot/penpot/pull/9747))
|
||||||
- Fix team invitation not automatically accepted after account validation [#9776](https://github.com/penpot/penpot/issues/9776) (PR: [#9782](https://github.com/penpot/penpot/pull/9782))
|
- Fix team invitation not automatically accepted after account validation [#9776](https://github.com/penpot/penpot/issues/9776) (PR: [#9782](https://github.com/penpot/penpot/pull/9782))
|
||||||
|
- Fix design tokens vanishing from the sidebar when a token name collides with a token-group prefix from another active set (e.g. `a` in one set and `a.b` in another); the colliding token is now kept and rendered as a broken pill [Github #9584](https://github.com/penpot/penpot/issues/9584)
|
||||||
|
|
||||||
|
|
||||||
## 2.15.4
|
## 2.15.4
|
||||||
|
|||||||
@ -553,10 +553,36 @@
|
|||||||
(defn sd-token-uuid [^js sd-token]
|
(defn sd-token-uuid [^js sd-token]
|
||||||
(uuid (.-uuid (.. sd-token -original -id))))
|
(uuid (.-uuid (.. sd-token -original -id))))
|
||||||
|
|
||||||
|
(defn- merge-name-collisions
|
||||||
|
"Re-attach tokens that `ctob/tokens-tree` / `backtrace-tokens-tree`
|
||||||
|
dropped because one token's name is a strict prefix of another's
|
||||||
|
(e.g. `a` vs `a.b` coming from two active sets). `assoc-in` in the
|
||||||
|
tree builder collapses such pairs, so StyleDictionary only sees one
|
||||||
|
of them and the other vanishes from the resolved map — and from the
|
||||||
|
sidebar, even though it still lives in the library (#9584).
|
||||||
|
|
||||||
|
We tag each dropped token with `:error.token/name-collision` so the
|
||||||
|
existing token-pill error rendering picks them up as broken pills,
|
||||||
|
matching the expected behaviour in the issue. Resolved tokens are
|
||||||
|
left untouched."
|
||||||
|
[tokens resolved]
|
||||||
|
(let [resolved-names (set (keys resolved))
|
||||||
|
dropped (->> tokens
|
||||||
|
(remove (fn [[k _]] (contains? resolved-names k)))
|
||||||
|
(map (fn [[k token]]
|
||||||
|
[k (assoc token
|
||||||
|
:errors
|
||||||
|
[(wte/error-with-value
|
||||||
|
:error.token/name-collision
|
||||||
|
(:name token))])]))
|
||||||
|
(into {}))]
|
||||||
|
(merge resolved dropped)))
|
||||||
|
|
||||||
(defn resolve-tokens
|
(defn resolve-tokens
|
||||||
[tokens]
|
[tokens]
|
||||||
(let [tokens-tree (ctob/tokens-tree tokens)]
|
(let [tokens-tree (ctob/tokens-tree tokens)]
|
||||||
(resolve-tokens-tree tokens-tree #(get tokens (sd-token-name %)))))
|
(->> (resolve-tokens-tree tokens-tree #(get tokens (sd-token-name %)))
|
||||||
|
(rx/map #(merge-name-collisions tokens %)))))
|
||||||
|
|
||||||
(defn resolve-tokens-interactive
|
(defn resolve-tokens-interactive
|
||||||
"Interactive check of resolving tokens.
|
"Interactive check of resolving tokens.
|
||||||
@ -579,7 +605,8 @@
|
|||||||
same :name path by just looking up that :id in the ids map."
|
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 %)))
|
||||||
|
(rx/map #(merge-name-collisions tokens %)))))
|
||||||
|
|
||||||
(defn resolve-tokens-with-verbose-errors [tokens]
|
(defn resolve-tokens-with-verbose-errors [tokens]
|
||||||
(resolve-tokens-tree
|
(resolve-tokens-tree
|
||||||
|
|||||||
@ -52,6 +52,16 @@
|
|||||||
{:error/code :error.token/number-too-large
|
{:error/code :error.token/number-too-large
|
||||||
:error/fn #(str (tr "errors.tokens.number-too-large" %))}
|
:error/fn #(str (tr "errors.tokens.number-too-large" %))}
|
||||||
|
|
||||||
|
;; Surfaced when a token name conflicts with a token-group prefix
|
||||||
|
;; across the active sets (e.g. one set defines `a`, another set
|
||||||
|
;; defines `a.b`). DTCG/StyleDictionary cannot represent both as
|
||||||
|
;; resolvable leaves, so the colliding token is preserved with this
|
||||||
|
;; error rather than silently disappearing from the sidebar — see
|
||||||
|
;; #9584.
|
||||||
|
:error.token/name-collision
|
||||||
|
{:error/code :error.token/name-collision
|
||||||
|
:error/fn #(str (tr "errors.tokens.name-collision" %))}
|
||||||
|
|
||||||
:error.style-dictionary/missing-reference
|
:error.style-dictionary/missing-reference
|
||||||
{:error/code :error.style-dictionary/missing-reference
|
{:error/code :error.style-dictionary/missing-reference
|
||||||
:error/fn #(str (tr "errors.tokens.missing-references") (str/join " " %))}
|
:error/fn #(str (tr "errors.tokens.missing-references") (str/join " " %))}
|
||||||
|
|||||||
@ -58,6 +58,45 @@
|
|||||||
(get-in resolved-tokens ["borderRadius.largeFn" :errors 0 :error/code])))
|
(get-in resolved-tokens ["borderRadius.largeFn" :errors 0 :error/code])))
|
||||||
(done))))))))
|
(done))))))))
|
||||||
|
|
||||||
|
;; Regression for #9584 — when one active set defines a token named
|
||||||
|
;; "a" and another defines "a.b", the tokens-tree builder collapses
|
||||||
|
;; them via assoc-in, so StyleDictionary only sees one. Previously
|
||||||
|
;; the other vanished from the sidebar entirely; now `resolve-tokens`
|
||||||
|
;; tags the dropped token with `:error.token/name-collision` so the
|
||||||
|
;; existing broken-pill rendering picks it up.
|
||||||
|
|
||||||
|
(t/deftest resolve-tokens-name-collision-test
|
||||||
|
(t/async
|
||||||
|
done
|
||||||
|
(t/testing "tokens colliding with a token-group prefix survive resolution as broken pills"
|
||||||
|
(let [tokens (-> (ctob/make-tokens-lib)
|
||||||
|
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-1)
|
||||||
|
:name "set-1"))
|
||||||
|
(ctob/add-set (ctob/make-token-set :id (cthi/new-id! :set-2)
|
||||||
|
:name "set-2"))
|
||||||
|
(ctob/add-token (cthi/id :set-1)
|
||||||
|
(ctob/make-token {:name "a"
|
||||||
|
:value "8px"
|
||||||
|
:type :border-radius}))
|
||||||
|
(ctob/add-token (cthi/id :set-2)
|
||||||
|
(ctob/make-token {:name "a.b"
|
||||||
|
:value "12px"
|
||||||
|
:type :border-radius}))
|
||||||
|
(ctob/get-all-tokens-map))]
|
||||||
|
(-> (sd/resolve-tokens tokens)
|
||||||
|
(rx/sub!
|
||||||
|
(fn [resolved-tokens]
|
||||||
|
(t/testing "both tokens are present in the resolved map"
|
||||||
|
(t/is (contains? resolved-tokens "a"))
|
||||||
|
(t/is (contains? resolved-tokens "a.b")))
|
||||||
|
(t/testing "the colliding token carries the name-collision error"
|
||||||
|
(let [errors (or (get-in resolved-tokens ["a" :errors])
|
||||||
|
(get-in resolved-tokens ["a.b" :errors]))]
|
||||||
|
(t/is (seq errors))
|
||||||
|
(t/is (= :error.token/name-collision
|
||||||
|
(-> errors first :error/code)))))
|
||||||
|
(done))))))))
|
||||||
|
|
||||||
(t/deftest resolve-tokens-interactive-test
|
(t/deftest resolve-tokens-interactive-test
|
||||||
(t/async
|
(t/async
|
||||||
done
|
done
|
||||||
|
|||||||
@ -8608,6 +8608,10 @@ msgstr "%s active sets"
|
|||||||
msgid "errors.tokens.number-too-large"
|
msgid "errors.tokens.number-too-large"
|
||||||
msgstr "Invalid token value. The resolved value is too large: %s"
|
msgstr "Invalid token value. The resolved value is too large: %s"
|
||||||
|
|
||||||
|
#: src/app/main/data/workspace/tokens/errors.cljs:60
|
||||||
|
msgid "errors.tokens.name-collision"
|
||||||
|
msgstr "Token name %s conflicts with a token group of the same name in another active set."
|
||||||
|
|
||||||
#: src/app/main/data/workspace/tokens/errors.cljs:73, src/app/main/data/workspace/tokens/warnings.cljs:15
|
#: src/app/main/data/workspace/tokens/errors.cljs:73, src/app/main/data/workspace/tokens/warnings.cljs:15
|
||||||
msgid "errors.tokens.opacity-range"
|
msgid "errors.tokens.opacity-range"
|
||||||
msgstr "Opacity must be between 0 and 100% or 0 and 1 (e.g. 50% or 0.5)."
|
msgstr "Opacity must be between 0 and 100% or 0 and 1 (e.g. 50% or 0.5)."
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user