🔧 Move token helpers to common.files

This commit is contained in:
Andrés Moya 2025-04-25 13:58:25 +02:00
parent a5bbe765b9
commit 3e0f38e8c3
11 changed files with 83 additions and 75 deletions

View file

@ -2,13 +2,13 @@
(:require
["@tokens-studio/sd-transforms" :as sd-transforms]
["style-dictionary$default" :as sd]
[app.common.files.tokens :as cft]
[app.common.logging :as l]
[app.common.schema :as sm]
[app.common.transit :as t]
[app.common.types.tokens-lib :as ctob]
[app.main.data.tinycolor :as tinycolor]
[app.main.ui.workspace.tokens.errors :as wte]
[app.main.ui.workspace.tokens.token :as wtt]
[app.main.ui.workspace.tokens.warnings :as wtw]
[app.util.time :as dt]
[beicon.v2.core :as rx]
@ -54,7 +54,7 @@
"Parses `value` of a numeric `sd-token` into a map like `{:value 1 :unit \"px\"}`.
If the `value` is not parseable and/or has missing references returns a map with `:errors`."
[value]
(let [parsed-value (wtt/parse-token-value value)
(let [parsed-value (cft/parse-token-value value)
out-of-bounds (or (>= (:value parsed-value) sm/max-safe-int)
(<= (:value parsed-value) sm/min-safe-int))]
(if (and parsed-value (not out-of-bounds))
@ -72,7 +72,7 @@
If the `value` is parseable but is out of range returns a map with `warnings`."
[value has-references?]
(let [parsed-value (wtt/parse-token-value value)
(let [parsed-value (cft/parse-token-value value)
out-of-scope (not (<= 0 (:value parsed-value) 1))
references (seq (ctob/find-token-value-references value))]
(cond
@ -98,7 +98,7 @@
If the `value` is parseable but is out of range returns a map with `warnings`."
[value has-references?]
(let [parsed-value (wtt/parse-token-value value)
(let [parsed-value (cft/parse-token-value value)
out-of-scope (< (:value parsed-value) 0)
references (seq (ctob/find-token-value-references value))]
(cond

View file

@ -8,6 +8,7 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.tokens :as cft]
[app.common.types.shape.layout :as ctsl]
[app.common.types.shape.radius :as ctsr]
[app.common.types.token :as ctt]
@ -23,7 +24,6 @@
[app.main.data.workspace.transforms :as dwt]
[app.main.data.workspace.undo :as dwu]
[app.main.store :as st]
[app.main.ui.workspace.tokens.token :as wtt]
[beicon.v2.core :as rx]
[clojure.set :as set]
[potok.v2.core :as ptk]))
@ -56,8 +56,8 @@
(keys))
[])
resolved-value (get-in resolved-tokens [(wtt/token-identifier token) :resolved-value])
tokenized-attributes (wtt/attributes-map attributes token)]
resolved-value (get-in resolved-tokens [(cft/token-identifier token) :resolved-value])
tokenized-attributes (cft/attributes-map attributes token)]
(rx/of
(st/emit! (ptk/event ::ev/event {::ev/name "apply-tokens"}))
(dwu/start-undo-transaction undo-id)
@ -80,7 +80,7 @@
ptk/WatchEvent
(watch [_ _ _]
(rx/of
(let [remove-token #(when % (wtt/remove-attributes-for-token attributes token %))]
(let [remove-token #(when % (cft/remove-attributes-for-token attributes token %))]
(dwsh/update-shapes
shape-ids
(fn [shape]
@ -95,7 +95,7 @@
(get token-properties (:type token))
unapply-tokens?
(wtt/shapes-token-applied? token shapes (or all-attributes attributes))
(cft/shapes-token-applied? token shapes (or all-attributes attributes))
shape-ids (map :id shapes)]
(if unapply-tokens?

View file

@ -0,0 +1,21 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.main.data.workspace.tokens.color
(:require
[app.common.files.tokens :as cft]
[app.main.data.tinycolor :as tinycolor]))
(defn color-bullet-color [token-color-value]
(when-let [tc (tinycolor/valid-color token-color-value)]
(if (tinycolor/alpha tc)
{:color (tinycolor/->hex-string tc)
:opacity (tinycolor/alpha tc)}
(tinycolor/->hex-string tc))))
(defn resolved-token-bullet-color [{:keys [resolved-value] :as token}]
(when (and resolved-value (cft/color-token? token))
(color-bullet-color resolved-value)))

View file

@ -7,8 +7,8 @@
(ns app.main.ui.workspace.tokens.components.controls.input-token-color-bullet
(:require-macros [app.main.style :as stl])
(:require
[app.main.data.workspace.tokens.color :as dwtc]
[app.main.ui.components.color-bullet :refer [color-bullet]]
[app.main.ui.workspace.tokens.token :as wtt]
[rumext.v2 :as mf]))
(def ^:private schema::input-token-color-bullet
@ -23,6 +23,6 @@
[:div {:data-testid "token-form-color-bullet"
:class (stl/css :input-token-color-bullet)
:on-click on-click}
(if-let [color' (wtt/color-bullet-color color)]
(if-let [color' (dwtc/color-bullet-color color)]
[:> color-bullet {:color color' :mini true}]
[:div {:class (stl/css :input-token-color-bullet-placeholder)}])])

View file

@ -9,6 +9,7 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.tokens :as cft]
[app.common.types.tokens-lib :as ctob]
[app.main.data.modal :as modal]
[app.main.data.workspace.shape-layout :as dwsl]
@ -18,7 +19,6 @@
[app.main.store :as st]
[app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.ds.foundations.assets.icon :refer [icon*]]
[app.main.ui.workspace.tokens.token :as wtt]
[app.util.dom :as dom]
[app.util.i18n :refer [tr]]
[app.util.timers :as timers]
@ -30,9 +30,9 @@
;; Actions ---------------------------------------------------------------------
(defn attribute-actions [token selected-shapes attributes]
(let [ids-by-attributes (wtt/shapes-ids-by-applied-attributes token selected-shapes attributes)
(let [ids-by-attributes (cft/shapes-ids-by-applied-attributes token selected-shapes attributes)
shape-ids (into #{} (map :id selected-shapes))]
{:all-selected? (wtt/shapes-applied-all? ids-by-attributes shape-ids attributes)
{:all-selected? (cft/shapes-applied-all? ids-by-attributes shape-ids attributes)
:shape-ids shape-ids
:selected-pred #(seq (% ids-by-attributes))}))

View file

@ -10,6 +10,7 @@
[app.common.colors :as c]
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.tokens :as cft]
[app.common.types.tokens-lib :as ctob]
[app.main.data.modal :as modal]
[app.main.data.style-dictionary :as sd]
@ -28,7 +29,6 @@
[app.main.ui.workspace.tokens.components.controls.input-token-color-bullet :refer [input-token-color-bullet*]]
[app.main.ui.workspace.tokens.components.controls.input-tokens :refer [input-tokens*]]
[app.main.ui.workspace.tokens.errors :as wte]
[app.main.ui.workspace.tokens.token :as wtt]
[app.main.ui.workspace.tokens.update :as wtu]
[app.main.ui.workspace.tokens.warnings :as wtw]
[app.util.dom :as dom]
@ -64,7 +64,7 @@
(let [path-exists-schema
(m/-simple-schema
{:type :token/name-exists
:pred #(not (wtt/token-name-path-exists? % tokens-tree))
:pred #(not (cft/token-name-path-exists? % tokens-tree))
:type-properties {:error/fn #(str "A token already exists at the path: " (:value %))}})]
(m/schema
[:and
@ -240,7 +240,7 @@
(let [create? (not (instance? ctob/Token token))
token (or token {:type token-type})
token-properties (dwta/get-token-properties token)
color? (wtt/color-token? token)
color? (cft/color-token? token)
selected-set-tokens (mf/deref refs/workspace-selected-token-set-tokens)
active-theme-tokens (cond-> (mf/deref refs/workspace-active-theme-sets-tokens)
@ -254,7 +254,7 @@
:interactive? true})
token-path (mf/use-memo
(mf/deps (:name token))
#(wtt/token-name->path (:name token)))
#(cft/token-name->path (:name token)))
selected-set-tokens-tree (mf/use-memo
(mf/deps token-path selected-set-tokens)
@ -329,7 +329,7 @@
value-input-ref (mf/use-ref nil)
value-ref (mf/use-var (:value token))
token-resolve-result* (mf/use-state (get resolved-tokens (wtt/token-identifier token)))
token-resolve-result* (mf/use-state (get resolved-tokens (cft/token-identifier token)))
token-resolve-result (deref token-resolve-result*)
set-resolve-value

View file

@ -1,145 +0,0 @@
(ns app.main.ui.workspace.tokens.token
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.main.data.tinycolor :as tinycolor]
[clojure.set :as set]
[cuerdas.core :as str]))
(def parseable-token-value-regexp
"Regexp that can be used to parse a number value out of resolved token value.
This regexp also trims whitespace around the value."
#"^\s*(-?[0-9]+\.?[0-9]*)(px|%)?\s*$")
(defn parse-token-value
"Parses a resolved value and separates the unit from the value.
Returns a map of {:value `number` :unit `string`}."
[value]
(cond
(number? value) {:value value}
(string? value) (when-let [[_ value unit] (re-find parseable-token-value-regexp value)]
(when-let [parsed-value (d/parse-double value)]
{:value parsed-value
:unit unit}))))
;; FIXME: looks very redundant function
(defn token-identifier
[{:keys [name] :as _token}]
name)
(defn attributes-map
"Creats an attributes map using collection of `attributes` for `id`."
[attributes token]
(->> (map (fn [attr] [attr (token-identifier token)]) attributes)
(into {})))
(defn remove-attributes-for-token
"Removes applied tokens with `token-id` for the given `attributes` set from `applied-tokens`."
[attributes token applied-tokens]
(let [attr? (set attributes)]
(->> (remove (fn [[k v]]
(and (attr? k)
(= v (token-identifier token))))
applied-tokens)
(into {}))))
(defn token-attribute-applied?
"Test if `token` is applied to a `shape` on single `token-attribute`."
[token shape token-attribute]
(when-let [id (dm/get-in shape [:applied-tokens token-attribute])]
(= (token-identifier token) id)))
(defn token-applied?
"Test if `token` is applied to a `shape` with at least one of the given `token-attributes`."
[token shape token-attributes]
(some #(token-attribute-applied? token shape %) token-attributes))
(defn shapes-token-applied?
"Test if `token` is applied to to any of `shapes` with at least one of the given `token-attributes`."
[token shapes token-attributes]
(some #(token-applied? token % token-attributes) shapes))
(defn shapes-ids-by-applied-attributes
[token shapes token-attributes]
(let [conj* (fnil conj #{})]
(reduce (fn [result shape]
(let [shape-id (dm/get-prop shape :id)]
(->> token-attributes
(filter #(token-attribute-applied? token shape %))
(reduce (fn [result attr]
(update result attr conj* shape-id))
result))))
{}
shapes)))
(defn shapes-applied-all? [ids-by-attributes shape-ids attributes]
(every? #(set/superset? (get ids-by-attributes %) shape-ids) attributes))
(defn token-name->path
"Splits token-name into a path vector split by `.` characters.
Will concatenate multiple `.` characters into one."
[token-name]
(str/split token-name #"\.+"))
(defn token-name->path-selector
"Splits token-name into map with `:path` and `:selector` using `token-name->path`.
`:selector` is the last item of the names path
`:path` is everything leading up the the `:selector`."
[token-name]
(let [path-segments (token-name->path token-name)
last-idx (dec (count path-segments))
[path [selector]] (split-at last-idx path-segments)]
{:path (seq path)
:selector selector}))
(defn token-name-path-exists?
"Traverses the path from `token-name` down a `token-tree` and checks if a token at that path exists.
It's not allowed to create a token inside a token. E.g.:
Creating a token with
{:name \"foo.bar\"}
in the tokens tree:
{\"foo\" {:name \"other\"}}"
[token-name token-names-tree]
(let [{:keys [path selector]} (token-name->path-selector token-name)
path-target (reduce
(fn [acc cur]
(let [target (get acc cur)]
(cond
;; Path segment doesn't exist yet
(nil? target) (reduced false)
;; A token exists at this path
(:name target) (reduced true)
;; Continue traversing the true
:else target)))
token-names-tree path)]
(cond
(boolean? path-target) path-target
(get path-target :name) true
:else (-> (get path-target selector)
(seq)
(boolean)))))
(defn color-token? [token]
(= (:type token) :color))
;; FIXME: this should be precalculated ?
(defn is-reference? [token]
(str/includes? (:value token) "{"))
(defn color-bullet-color [token-color-value]
(when-let [tc (tinycolor/valid-color token-color-value)]
(if (tinycolor/alpha tc)
{:color (tinycolor/->hex-string tc)
:opacity (tinycolor/alpha tc)}
(tinycolor/->hex-string tc))))
(defn resolved-token-bullet-color [{:keys [resolved-value] :as token}]
(when (and resolved-value (color-token? token))
(color-bullet-color resolved-value)))

View file

@ -11,12 +11,13 @@
(:require
[app.common.data :as d]
[app.common.files.helpers :as cfh]
[app.common.files.tokens :as cft]
[app.main.data.workspace.tokens.application :as dwta]
[app.main.data.workspace.tokens.color :as dwtc]
[app.main.refs :as refs]
[app.main.ui.components.color-bullet :refer [color-bullet]]
[app.main.ui.ds.foundations.assets.icon :refer [icon*]]
[app.main.ui.ds.foundations.utilities.token.token-status :refer [token-status-icon*]]
[app.main.ui.workspace.tokens.token :as wtt]
[app.util.dom :as dom]
[app.util.i18n :refer [tr]]
[cuerdas.core :as str]
@ -80,6 +81,7 @@
:y "Y"})
;; Helper functions
(defn partially-applied-attr
"Translates partially applied attributes based on the dictionary."
[app-token-keys is-applied {:keys [attributes all-attributes]}]
@ -156,9 +158,9 @@
(defn- applied-all-attributes?
[token selected-shapes attributes]
(let [ids-by-attributes (wtt/shapes-ids-by-applied-attributes token selected-shapes attributes)
(let [ids-by-attributes (cft/shapes-ids-by-applied-attributes token selected-shapes attributes)
shape-ids (into #{} xf:map-id selected-shapes)]
(wtt/shapes-applied-all? ids-by-attributes shape-ids attributes)))
(cft/shapes-applied-all? ids-by-attributes shape-ids attributes)))
(mf/defc token-pill*
{::mf/wrap [mf/memo]}
@ -166,7 +168,7 @@
(let [{:keys [name value errors]} token
has-selected? (pos? (count selected-shapes))
is-reference? (wtt/is-reference? token)
is-reference? (cft/is-reference? token)
contains-path? (str/includes? name ".")
{:keys [attributes all-attributes]}
@ -179,7 +181,7 @@
applied?
(if has-selected?
(wtt/shapes-token-applied? token selected-shapes (d/nilv all-attributes attributes))
(cft/shapes-token-applied? token selected-shapes (d/nilv all-attributes attributes))
false)
half-applied?
@ -201,10 +203,10 @@
no-valid-value)
color
(when (wtt/color-token? token)
(when (cft/color-token? token)
(let [theme-token (get active-theme-tokens (:name token))]
(or (wtt/resolved-token-bullet-color theme-token)
(wtt/resolved-token-bullet-color token))))
(or (dwtc/resolved-token-bullet-color theme-token)
(dwtc/resolved-token-bullet-color token))))
on-click
(mf/use-fn