mirror of
https://github.com/penpot/penpot.git
synced 2026-03-22 18:33:45 +00:00
@@ -147,6 +147,27 @@
|
||||
#(and (some? tokens-tree)
|
||||
(not (ctob/token-name-path-exists? % tokens-tree)))]])
|
||||
|
||||
(defn make-node-token-name-schema
|
||||
"Dynamically generates a schema to check a token node name, adding translated error messages
|
||||
and two additional validations:
|
||||
- Min and max length.
|
||||
- Checks if other token with a path derived from the name already exists at `tokens-tree`.
|
||||
e.g. it's not allowed to create a token `foo.bar` if a token `foo` already exists."
|
||||
[active-tokens tokens-tree node]
|
||||
[:and
|
||||
[:string {:min 1 :max 255 :error/fn #(str (:value %) (tr "workspace.tokens.token-name-length-validation-error"))}]
|
||||
(-> cto/schema:token-node-name
|
||||
(sm/update-properties assoc :error/fn #(str (:value %) (tr "workspace.tokens.token-name-validation-error"))))
|
||||
[:fn {:error/fn #(tr "workspace.tokens.token-name-duplication-validation-error" (:value %))}
|
||||
(fn [name]
|
||||
(let [current-path (:path node)
|
||||
current-name (:name node)
|
||||
new-tokens (ctob/update-tokens-group active-tokens current-path current-name name)]
|
||||
(and (some? new-tokens)
|
||||
(some (fn [[token-name _]]
|
||||
(not (ctob/token-name-path-exists? token-name tokens-tree)))
|
||||
new-tokens))))]])
|
||||
|
||||
(def schema:token-description
|
||||
[:string {:max 2048 :error/fn #(tr "errors.field-max-length" 2048)}])
|
||||
|
||||
@@ -165,6 +186,11 @@
|
||||
(when (and name value)
|
||||
(not (cto/token-value-self-reference? name value))))]])
|
||||
|
||||
(defn make-node-token-schema
|
||||
[active-tokens tokens-tree node]
|
||||
[:map
|
||||
[:name (make-node-token-name-schema active-tokens tokens-tree node)]])
|
||||
|
||||
(defn convert-dtcg-token
|
||||
"Convert token attributes as they come from a decoded json, with DTCG types, to internal types.
|
||||
Eg. From this:
|
||||
|
||||
@@ -136,6 +136,9 @@
|
||||
(def token-name-validation-regex
|
||||
#"^[a-zA-Z0-9_-][a-zA-Z0-9$_-]*(\.[a-zA-Z0-9$_-]+)*$")
|
||||
|
||||
(def token-node-name-validation-regex
|
||||
#"^[a-zA-Z0-9_-][a-zA-Z0-9$_-]*(\.[a-zA-Z0-9$_-]+)*$")
|
||||
|
||||
(def schema:token-name
|
||||
"A token name can contains letters, numbers, underscores the character $ and dots, but
|
||||
not start with $ or end with a dot. The $ character does not have any special meaning,
|
||||
@@ -153,6 +156,14 @@
|
||||
:gen/gen sg/text}
|
||||
token-ref-validation-regex])
|
||||
|
||||
(def schema:token-node-name
|
||||
"A token node name can contains letters, numbers, underscores and the character $, but
|
||||
not start with $ or a dot, or end with a dot. The $ character does not have any special meaning,
|
||||
but dots separate token groups (e.g. color.primary.background)."
|
||||
[:re {:title "TokenNodeName"
|
||||
:gen/gen sg/text}
|
||||
token-node-name-validation-regex])
|
||||
|
||||
(def schema:token-type
|
||||
[::sm/one-of {:decode/json (fn [type]
|
||||
(if (string? type)
|
||||
|
||||
@@ -153,6 +153,18 @@
|
||||
tokens)]
|
||||
(group-by :type tokens')))
|
||||
|
||||
(defn rename-path
|
||||
"Renames a node or token path segment with a new name.
|
||||
If token is provided, it renames a token path, otherwise it renames a node path."
|
||||
([node new-name]
|
||||
(rename-path node nil new-name))
|
||||
([node token new-name]
|
||||
(let [element (if token (:name token) (:path node))
|
||||
split-path (cpn/split-path element :separator ".")
|
||||
updated-split-element-name (assoc split-path (:depth node) new-name)
|
||||
new-element-path (cpn/join-path updated-split-element-name :separator "." :with-spaces? false)]
|
||||
new-element-path)))
|
||||
|
||||
;; === Token Set
|
||||
|
||||
(defprotocol ITokenSet
|
||||
@@ -1490,6 +1502,30 @@ Will return a value that matches this schema:
|
||||
(seq)
|
||||
(boolean)))))
|
||||
|
||||
(defn update-tokens-group
|
||||
"Updates the active tokens path when renaming a group node.
|
||||
- Filters tokens whose path matches the current path prefix
|
||||
- Replaces the token name with the new name
|
||||
- Updates the :path value in the token object
|
||||
|
||||
active-tokens: map of token-name to token-object for all active tokens in the set
|
||||
current-path: the path of the group being renamed, e.g. \"foo.bar\"
|
||||
current-name: the current name of the group being renamed, e.g. \"bar\"
|
||||
new-name: the new name for the group being renamed, e.g. \"baz\""
|
||||
|
||||
[active-tokens current-path current-name new-name]
|
||||
(let [path-prefix (str/replace current-path current-name "")]
|
||||
(mapv (fn [[token-path token-obj]]
|
||||
(if (str/starts-with? token-path path-prefix)
|
||||
(let [new-token-path (str/replace token-path current-name new-name)
|
||||
new-token-obj (-> token-obj
|
||||
(assoc :name new-token-path)
|
||||
(cond-> (:path token-obj)
|
||||
(assoc :path (str/replace (:path token-obj) current-name new-name))))]
|
||||
[new-token-path new-token-obj])
|
||||
[token-path token-obj]))
|
||||
active-tokens)))
|
||||
|
||||
;; === Import / Export from JSON format
|
||||
|
||||
;; Supported formats:
|
||||
|
||||
Reference in New Issue
Block a user