diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index e89f7c91da..4cb6cedc60 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -760,6 +760,21 @@ default v)))) +(defn percent? + [v] + (str/numeric? (str/rtrim v "%"))) + +(defn parse-percent + ([v] + (parse-percent v nil)) + ([v default] + (if (str/ends-with? v "%") + (let [v (impl-parse-double (str/trim v "%"))] + (if (or (nil? v) (nan? v)) + default + (/ v 100))) + (parse-double v default)))) + (defn parse-uuid [v] (try diff --git a/common/src/app/common/files/tokens.cljc b/common/src/app/common/files/tokens.cljc index 2da869cccf..e8f1208058 100644 --- a/common/src/app/common/files/tokens.cljc +++ b/common/src/app/common/files/tokens.cljc @@ -31,18 +31,56 @@ (def schema:token-value-generic [::sm/text {:error/fn token-value-empty-fn}]) +(def schema:token-value-numeric + [:and + [::sm/text {:error/fn token-value-empty-fn}] + [:fn {:error/fn #(tr "workspace.tokens.invalid-value" (:value %))} + (fn [value] + (if (str/numeric? value) + (let [n (d/parse-double value)] + (some? n)) + true))]]) ;; Leave references or formulas to be checked by the resolver + +(def schema:token-value-percent + [:and + [::sm/text {:error/fn token-value-empty-fn}] + [:fn {:error/fn #(tr "workspace.tokens.value-with-percent" (:value %))} + (fn [value] + (if (d/percent? value) + (let [v (d/parse-percent value)] + (some? v)) + true))]]) ;; Leave references or formulas to be checked by the resolver + (def schema:token-value-composite-ref [::sm/text {:error/fn token-value-empty-fn}]) +(def schema:token-value-opacity + [:and + [::sm/text {:error/fn token-value-empty-fn}] + [:fn {:error/fn #(tr "workspace.tokens.opacity-range")} + (fn [opacity] + (if (str/numeric? opacity) + (let [n (d/parse-percent opacity)] + (and (some? n) (<= 0 n 1))) + true))]]) ;; Leave references or formulas to be checked by the resolver + (def schema:token-value-font-family - [:vector ::sm/text]) + [:or + [:vector ::sm/text] + cto/schema:token-ref]) + +(def schema:token-value-font-weight + [:or + [:fn {:error/fn #(tr "workspace.tokens.invalid-font-weight-token-value")} + cto/valid-font-weight-variant] + ::sm/text]) ;; Leave references or formulas to be checked by the resolver (def schema:token-value-typography-map [:map [:font-family {:optional true} schema:token-value-font-family] - [:font-weight {:optional true} schema:token-value-generic] - [:font-size {:optional true} schema:token-value-generic] - [:line-height {:optional true} schema:token-value-generic] + [:font-size {:optional true} schema:token-value-numeric] + [:font-weight {:optional true} schema:token-value-font-weight] + [:line-height {:optional true} schema:token-value-percent] [:letter-spacing {:optional true} schema:token-value-generic] [:paragraph-spacing {:optional true} schema:token-value-generic] [:text-decoration {:optional true} schema:token-value-generic] @@ -84,7 +122,10 @@ [token-type] [:multi {:dispatch (constantly token-type) :title "Token Value"} + [:opacity schema:token-value-opacity] [:font-family schema:token-value-font-family] + [:font-size schema:token-value-numeric] + [:font-weight schema:token-value-font-weight] [:typography schema:token-value-typography] [:shadow schema:token-value-shadow] [::m/default schema:token-value-generic]]) @@ -169,7 +210,7 @@ [tokens-lib set-id] [:and [:string {:min 1 :max 255 :error/fn #(str (:value %) (tr "workspace.tokens.token-name-length-validation-error"))}] - [:fn {:error/fn #(tr "errors.token-set-already-exists" (:value %))} + [:fn {:error/fn #(tr "errors.token-set-already-exists")} (fn [name] (or (nil? tokens-lib) (let [set (ctob/get-set-by-name tokens-lib name)] @@ -196,7 +237,7 @@ [tokens-lib name theme-id] [:and [:string {:min 0 :max 255 :error/fn #(str (:value %) (tr "workspace.tokens.token-name-length-validation-error"))}] - [:fn {:error/fn #(tr "errors.token-theme-already-exists" (:value %))} + [:fn {:error/fn #(tr "errors.token-theme-already-exists")} (fn [group] (or (nil? tokens-lib) (let [theme (ctob/get-theme-by-name tokens-lib group name)] diff --git a/common/src/app/common/types/token.cljc b/common/src/app/common/types/token.cljc index 5f307ed223..e3e541da33 100644 --- a/common/src/app/common/types/token.cljc +++ b/common/src/app/common/types/token.cljc @@ -143,6 +143,15 @@ :gen/gen sg/text} token-name-validation-regex]) +(def token-ref-validation-regex + #"^\{[a-zA-Z0-9_-][a-zA-Z0-9$_-]*(\.[a-zA-Z0-9$_-]+)*\}$") + +(def schema:token-ref + "A token reference is a token name enclosed in {}." + [:re {:title "TokenRef" + :gen/gen sg/text} + token-ref-validation-regex]) + (def schema:token-type [::sm/one-of {:decode/json (fn [type] (if (string? type) diff --git a/exporter/src/app/browser.cljs b/exporter/src/app/browser.cljs index 526ae77380..0da27c2609 100644 --- a/exporter/src/app/browser.cljs +++ b/exporter/src/app/browser.cljs @@ -100,12 +100,14 @@ (def browser-pool-factory (letfn [(create [] - (p/let [opts #js {:args #js ["--allow-insecure-localhost" "--font-render-hinting=none"]} - browser (.launch pw/chromium opts) - id (swap! pool-browser-id inc)] - (l/info :origin "factory" :action "create" :browser-id id) - (unchecked-set browser "__id" id) - browser)) + (-> (p/let [opts #js {:args #js ["--allow-insecure-localhost" "--font-render-hinting=none"]} + browser (.launch pw/chromium opts) + id (swap! pool-browser-id inc)] + (l/info :origin "factory" :action "create" :browser-id id) + (unchecked-set browser "__id" id) + browser) + (p/catch (fn [cause] + (l/error :hint "Cannot launch the headless browser" :cause cause))))) (destroy [obj] (let [id (unchecked-get obj "__id")] diff --git a/exporter/src/app/handlers/export_shapes.cljs b/exporter/src/app/handlers/export_shapes.cljs index 29a92df61e..49913fd011 100644 --- a/exporter/src/app/handlers/export_shapes.cljs +++ b/exporter/src/app/handlers/export_shapes.cljs @@ -47,12 +47,13 @@ (s/def ::params (s/keys :req-un [::exports ::profile-id] - :opt-un [::wait ::name ::skip-children])) + :opt-un [::wait ::name ::skip-children ::force-multiple])) (defn handler - [{:keys [:request/auth-token] :as exchange} {:keys [exports] :as params}] + [{:keys [:request/auth-token] :as exchange} {:keys [exports force-multiple] :as params}] (let [exports (prepare-exports exports auth-token)] - (if (and (= 1 (count exports)) + (if (and (not force-multiple) + (= 1 (count exports)) (= 1 (count (-> exports first :objects)))) (handle-single-export exchange (-> params (assoc :export (first exports)) diff --git a/frontend/src/app/main/data/exports/assets.cljs b/frontend/src/app/main/data/exports/assets.cljs index 4355ad7ef9..f2c8315a90 100644 --- a/frontend/src/app/main/data/exports/assets.cljs +++ b/frontend/src/app/main/data/exports/assets.cljs @@ -195,7 +195,7 @@ params {:exports exports :cmd cmd :profile-id profile-id - :wait false} + :force-multiple true} progress-stream (->> (ws/get-rcv-stream ws-conn) diff --git a/frontend/src/app/main/data/plugins.cljs b/frontend/src/app/main/data/plugins.cljs index 5304681df4..2a0192340b 100644 --- a/frontend/src/app/main/data/plugins.cljs +++ b/frontend/src/app/main/data/plugins.cljs @@ -14,6 +14,7 @@ [app.main.data.modal :as modal] [app.main.data.notifications :as ntf] [app.main.store :as st] + [app.plugins.flags :as pflag] [app.plugins.register :as preg] [app.util.globals :as ug] [app.util.http :as http] @@ -44,20 +45,6 @@ (update [_ state] (update-in state [:workspace-local :open-plugins] (fnil conj #{}) id)))) -(defn reset-plugin-flags - [id] - (ptk/reify ::reset-plugin-flags - ptk/UpdateEvent - (update [_ state] - (update-in state [:workspace-local :plugin-flags] assoc id {})))) - -(defn set-plugin-flag - [id key value] - (ptk/reify ::set-plugin-flag - ptk/UpdateEvent - (update [_ state] - (update-in state [:workspace-local :plugin-flags id] assoc key value)))) - (defn remove-current-plugin [id] (ptk/reify ::remove-current-plugin @@ -83,8 +70,8 @@ (defn- load-plugin! [{:keys [plugin-id name description host code icon permissions] :as params}] (try - (st/emit! (save-current-plugin plugin-id) - (reset-plugin-flags plugin-id)) + (st/emit! (pflag/clear plugin-id) + (save-current-plugin plugin-id)) (.ɵloadPlugin ^js ug/global diff --git a/frontend/src/app/main/data/tokenscript.cljs b/frontend/src/app/main/data/tokenscript.cljs index 83a09d35e8..22e07efc66 100644 --- a/frontend/src/app/main/data/tokenscript.cljs +++ b/frontend/src/app/main/data/tokenscript.cljs @@ -69,6 +69,10 @@ (and (number-with-unit-symbol? v) (= (.-unit v) "rem"))) +(defn percent-number-with-unit? [v] + (and (number-with-unit-symbol? v) + (= (.-unit v) "%"))) + (defn rem->px [^js v] (* (.-value v) 16)) @@ -87,10 +91,12 @@ (defn tokenscript-symbols->penpot-unit [^js v] (cond + (nil? v) nil (structured-token? v) (structured-token->penpot-map v) (list-symbol? v) (structured-token->penpot-map v) (color-symbol? v) (.-value (.to v "hex")) (rem-number-with-unit? v) (rem->px v) + (percent-number-with-unit? v) (/ (.-value v) 100) :else (.-value v))) ;; Processors ------------------------------------------------------------------ diff --git a/frontend/src/app/main/data/workspace/tokens/import_export.cljs b/frontend/src/app/main/data/workspace/tokens/import_export.cljs index 7370da7921..32ba61fd70 100644 --- a/frontend/src/app/main/data/workspace/tokens/import_export.cljs +++ b/frontend/src/app/main/data/workspace/tokens/import_export.cljs @@ -8,10 +8,11 @@ (:require [app.common.json :as json] [app.common.path-names :as cpn] - [app.common.types.tokens-lib :as ctob] + [app.config :as cf] [app.main.data.notifications :as ntf] [app.main.data.style-dictionary :as sd] + [app.main.data.tokenscript :as ts] [app.main.data.workspace.tokens.errors :as wte] [app.main.store :as st] [app.util.i18n :refer [tr]] @@ -74,15 +75,18 @@ (when unknown-tokens (st/emit! (show-unknown-types-warning unknown-tokens))) (try - (->> (ctob/get-all-tokens-map tokens-lib) - (sd/resolve-tokens-with-verbose-errors) - (rx/map (fn [_] - tokens-lib)) - (rx/catch (fn [sd-error] - (let [reference-errors (extract-reference-errors sd-error)] - (if reference-errors - (rx/of tokens-lib) - (throw (wte/error-ex-info :error.import/style-dictionary-unknown-error sd-error sd-error))))))) + (let [tokens-tree (ctob/get-all-tokens-map tokens-lib) + resolved-tokens (if (contains? cf/flags :tokenscript) + (rx/of (ts/resolve-tokens tokens-tree)) + (sd/resolve-tokens-with-verbose-errors tokens-tree))] + (->> resolved-tokens + (rx/map (fn [_] + tokens-lib)) + (rx/catch (fn [sd-error] + (let [reference-errors (extract-reference-errors sd-error)] + (if reference-errors + (rx/of tokens-lib) + (throw (wte/error-ex-info :error.import/style-dictionary-unknown-error sd-error sd-error)))))))) (catch js/Error e (throw (wte/error-ex-info :error.import/style-dictionary-unknown-error "" e))))) diff --git a/frontend/src/app/main/data/workspace/tokens/propagation.cljs b/frontend/src/app/main/data/workspace/tokens/propagation.cljs index 7ba5c3970c..97e54a8f0b 100644 --- a/frontend/src/app/main/data/workspace/tokens/propagation.cljs +++ b/frontend/src/app/main/data/workspace/tokens/propagation.cljs @@ -6,13 +6,16 @@ (ns app.main.data.workspace.tokens.propagation (:require + [app.common.data :as d] [app.common.files.helpers :as cfh] [app.common.logging :as l] [app.common.time :as ct] [app.common.types.token :as ctt] [app.common.types.tokens-lib :as ctob] + [app.config :as cf] [app.main.data.helpers :as dsh] [app.main.data.style-dictionary :as sd] + [app.main.data.tokenscript :as ts] [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.thumbnails :as dwt] [app.main.data.workspace.tokens.application :as dwta] @@ -210,10 +213,13 @@ (ptk/reify ::propagate-workspace-tokens ptk/WatchEvent (watch [_ state _] - (when-let [tokens-lib (-> (dsh/lookup-file-data state) - (get :tokens-lib))] - (->> (ctob/get-tokens-in-active-sets tokens-lib) - (sd/resolve-tokens) + (when-let [tokens-tree (-> (dsh/lookup-file-data state) + (get :tokens-lib) + (ctob/get-tokens-in-active-sets))] + (->> (if (contains? cf/flags :tokenscript) + (rx/of (-> (ts/resolve-tokens tokens-tree) + (d/update-vals #(update % :resolved-value ts/tokenscript-symbols->penpot-unit)))) + (sd/resolve-tokens tokens-tree)) (rx/mapcat (fn [sd-tokens] (let [undo-id (js/Symbol)] (rx/concat diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index e7d958462c..706a7577a8 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -1173,7 +1173,8 @@ (when add-component-to-variant? (rx/of (ev/event {::ev/name "add-component-to-variant"}))) (when add-new-variant? - (rx/of (ev/event {::ev/name "add-new-variant" ::ev/origin "workspace:move-shapes-to-frame"})))))))) + (rx/of (ev/event {::ev/name "add-new-variant" + ::ev/origin "workspace:move-shapes-to-frame"})))))))) (defn- get-displacement "Retrieve the correct displacement delta point for the diff --git a/frontend/src/app/main/ui/workspace/tokens/management.cljs b/frontend/src/app/main/ui/workspace/tokens/management.cljs index 1f124b7b8b..0ff4deafa4 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management.cljs @@ -143,8 +143,7 @@ (let [token-ids (set tokens-in-path-ids) remaining-tokens (filter (fn [token] (not (contains? token-ids (:id token)))) - selected-token-set-tokens) - _ (prn "Remaining tokens:" remaining-tokens)] + selected-token-set-tokens)] (seq remaining-tokens)))) delete-token diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/color_input.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/color_input.cljs index b87bb0d675..c9c2f0aaf0 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/color_input.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/color_input.cljs @@ -13,8 +13,10 @@ [app.common.types.color :as cl] [app.common.types.token :as cto] [app.common.types.tokens-lib :as ctob] + [app.config :as cf] [app.main.data.style-dictionary :as sd] [app.main.data.tinycolor :as tinycolor] + [app.main.data.tokenscript :as ts] [app.main.data.workspace.tokens.format :as dwtf] [app.main.refs :as refs] [app.main.ui.ds.controls.input :as ds] @@ -70,11 +72,15 @@ (dissoc (:name prev-token)) (update (:name token) #(ctob/make-token (merge % prev-token token))))] - (->> tokens - (sd/resolve-tokens-interactive) + (->> (if (contains? cf/flags :tokenscript) + (rx/of (ts/resolve-tokens tokens)) + (sd/resolve-tokens-interactive tokens)) (rx/mapcat (fn [resolved-tokens] - (let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens (:name token))] + (let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens (:name token)) + resolved-value (if (contains? cf/flags :tokenscript) + (ts/tokenscript-symbols->penpot-unit resolved-value) + resolved-value)] (if resolved-value (rx/of {:value resolved-value}) (rx/of {:error (first errors)})))))))) diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/fonts_combobox.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/fonts_combobox.cljs index df76d47113..057419dc9c 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/fonts_combobox.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/fonts_combobox.cljs @@ -10,7 +10,9 @@ [app.common.data :as d] [app.common.types.token :as cto] [app.common.types.tokens-lib :as ctob] + [app.config :as cf] [app.main.data.style-dictionary :as sd] + [app.main.data.tokenscript :as ts] [app.main.fonts :as fonts] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.controls.input :refer [input*]] @@ -49,28 +51,30 @@ ;; validate data within the form state. (defn- resolve-value - [tokens prev-token token-name value] - (let [valid-token-name? - (and (string? token-name) - (re-matches cto/token-name-validation-regex token-name)) + [tokens prev-token _token-name value] + (let [tmp-value (cto/split-font-family value) + tmp-name "__PENPOT__FONT_FAMILY__PLACEHOLDER__" + ;; Create a temporary font-family token to validate the value token - {:value (cto/split-font-family value) - :name (if (or (not valid-token-name?) (str/blank? token-name)) - "__PENPOT__TOKEN__NAME__PLACEHOLDER__" - token-name)} + {:name tmp-name + :type :font-family + :value (if (= (:type prev-token) :typography) + (assoc (:value prev-token) :font-family tmp-value) + tmp-value)} tokens - (-> tokens - ;; Remove previous token when renaming a token - (dissoc (:name prev-token)) - (update (:name token) #(ctob/make-token (merge % prev-token token))))] + (update tokens (:name token) #(ctob/make-token (merge % prev-token token)))] - (->> tokens - (sd/resolve-tokens-interactive) + (->> (if (contains? cf/flags :tokenscript) + (rx/of (ts/resolve-tokens tokens)) + (sd/resolve-tokens-interactive tokens)) (rx/mapcat (fn [resolved-tokens] - (let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens (:name token))] + (let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens (:name token)) + resolved-value (if (contains? cf/flags :tokenscript) + (ts/tokenscript-symbols->penpot-unit resolved-value) + resolved-value)] (if resolved-value (rx/of {:value resolved-value}) (rx/of {:error (first errors)})))))))) @@ -176,7 +180,6 @@ (let [message (tr "workspace.tokens.resolved-value" value)] (swap! form update :extra-errors dissoc input-name) (reset! hint* {:message message :type "hint"})))))))] - (fn [] (rx/dispose! subs)))) diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs index 6b177aa243..6ab3f2786b 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs @@ -175,7 +175,10 @@ (sd/resolve-tokens-interactive) (rx/mapcat (fn [resolved-tokens] - (let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens (:name token))] + (let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens (:name token)) + resolved-value (if (contains? cf/flags :tokenscript) + (ts/tokenscript-symbols->penpot-unit resolved-value) + resolved-value)] (if resolved-value (rx/of {:value resolved-value}) (rx/of {:error (first errors)})))))))) diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/generic_form.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/generic_form.cljs index b0f36ec06c..f5541f8a40 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/forms/generic_form.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/generic_form.cljs @@ -36,9 +36,9 @@ [rumext.v2 :as mf])) (defn get-value-for-validator - [active-tab value value-subfield form-type] + [active-tab value value-subfield value-type] - (case form-type + (case value-type :indexed (if (= active-tab :reference) (:reference value) @@ -62,7 +62,7 @@ make-schema input-component initial - type + value-type value-subfield input-value-placeholder] :as props}] @@ -178,13 +178,13 @@ on-submit (mf/use-fn - (mf/deps validate-token token tokens token-type value-subfield type active-tab on-remap-token on-rename-token is-create) + (mf/deps validate-token token tokens token-type value-subfield value-type active-tab on-remap-token on-rename-token is-create) (fn [form _event] (let [name (get-in @form [:clean-data :name]) path (str (d/name token-type) "." name) description (get-in @form [:clean-data :description]) value (get-in @form [:clean-data :value]) - value-for-validation (get-value-for-validator active-tab value value-subfield type)] + value-for-validation (get-value-for-validator active-tab value value-subfield value-type)] (->> (validate-token {:token-value value-for-validation :token-name name :token-description description @@ -245,7 +245,7 @@ :auto-focus true}]] [:div {:class (stl/css :input-row)} - (case type + (case value-type :indexed [:> input-component {:token token diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/shadow.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/shadow.cljs index 9bf6fa32a2..722683d54a 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/forms/shadow.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/shadow.cljs @@ -365,7 +365,7 @@ :token-type token-type :initial initial :make-schema make-schema - :type :indexed + :value-type :indexed :value-subfield :shadow :input-component tabs-wrapper* :validator validate-shadow-token})] diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/typography.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/typography.cljs index 37a7fda7ca..cb926f72fd 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/forms/typography.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/typography.cljs @@ -300,6 +300,6 @@ :make-schema make-schema :token token :validator validate-typography-token - :type :composite + :value-type :composite :input-component tabs-wrapper*})] [:> generic/form* props])) diff --git a/frontend/src/app/main/ui/workspace/tokens/management/forms/validators.cljs b/frontend/src/app/main/ui/workspace/tokens/management/forms/validators.cljs index ab04acbd64..4fb9be3e4f 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/forms/validators.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/forms/validators.cljs @@ -4,7 +4,9 @@ [app.common.schema :as sm] [app.common.types.token :as cto] [app.common.types.tokens-lib :as ctob] + [app.config :as cf] [app.main.data.style-dictionary :as sd] + [app.main.data.tokenscript :as ts] [app.main.data.workspace.tokens.errors :as wte] [beicon.v2.core :as rx] [cuerdas.core :as str])) @@ -36,14 +38,20 @@ :always (update (:name token) #(ctob/make-token (merge % prev-token token))))] - (->> tokens' - (sd/resolve-tokens-interactive) + + (->> (if (contains? cf/flags :tokenscript) + (rx/of (ts/resolve-tokens tokens')) + (sd/resolve-tokens-interactive tokens')) (rx/mapcat (fn [resolved-tokens] - (let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens (:name token))] + (let [resolved-token (cond-> (get resolved-tokens (:name token)) + (contains? cf/flags :tokenscript) + (update :resolved-value ts/tokenscript-symbols->penpot-unit))] (cond - resolved-value (rx/of resolved-token) - :else (rx/throw {:errors (or (seq errors) + (:resolved-value resolved-token) + (rx/of resolved-token) + + :else (rx/throw {:errors (or (seq (:errors resolved-token)) [(wte/get-error-code :error/unknown-error)])})))))))) (defn- validate-token-with [token validators] diff --git a/frontend/src/app/main/ui/workspace/tokens/management/token_pill.cljs b/frontend/src/app/main/ui/workspace/tokens/management/token_pill.cljs index 94ac737ed8..c76651c151 100644 --- a/frontend/src/app/main/ui/workspace/tokens/management/token_pill.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/management/token_pill.cljs @@ -176,9 +176,10 @@ (mf/defc token-pill* {::mf/wrap [mf/memo]} [{:keys [on-click token on-context-menu selected-shapes is-selected-inside-layout active-theme-tokens]}] - (let [{:keys [name value errors type]} token + (let [{:keys [name value type]} token resolved-token (get active-theme-tokens (:name token)) + errors (:errors resolved-token) has-selected? (pos? (count selected-shapes)) is-reference? (cfo/is-reference? token) diff --git a/frontend/src/app/plugins/flags.cljs b/frontend/src/app/plugins/flags.cljs index 0e8a10a5da..a9f1a6dce7 100644 --- a/frontend/src/app/plugins/flags.cljs +++ b/frontend/src/app/plugins/flags.cljs @@ -6,10 +6,30 @@ (ns app.plugins.flags (:require - [app.main.data.plugins :as dp] + [app.common.data.macros :as dm] [app.main.store :as st] [app.plugins.utils :as u] - [app.util.object :as obj])) + [app.util.object :as obj] + [potok.v2.core :as ptk])) + +(defn natural-child-ordering? + [plugin-id] + (boolean + (dm/get-in @st/state [:plugins :flags plugin-id :natural-child-ordering]))) + +(defn clear + [id] + (ptk/reify ::reset + ptk/UpdateEvent + (update [_ state] + (update-in state [:plugins :flags] assoc id {})))) + +(defn- set-flag + [id key value] + (ptk/reify ::set-flag + ptk/UpdateEvent + (update [_ state] + (update-in state [:plugins :flags id] assoc key value)))) (defn flags-proxy [plugin-id] @@ -17,11 +37,7 @@ :naturalChildOrdering {:this false :get - (fn [] - (boolean - (get-in - @st/state - [:workspace-local :plugin-flags plugin-id :natural-child-ordering]))) + (fn [] (natural-child-ordering? plugin-id)) :set (fn [value] @@ -30,4 +46,4 @@ (u/display-not-valid :naturalChildOrdering value) :else - (st/emit! (dp/set-plugin-flag plugin-id :natural-child-ordering value))))})) + (st/emit! (set-flag plugin-id :natural-child-ordering value))))})) diff --git a/frontend/src/app/plugins/flex.cljs b/frontend/src/app/plugins/flex.cljs index 4c55edec3b..e8e8ff357f 100644 --- a/frontend/src/app/plugins/flex.cljs +++ b/frontend/src/app/plugins/flex.cljs @@ -259,7 +259,7 @@ (u/display-not-valid :appendChild child) :else - (let [child-id (obj/get child "$id")] + (let [child-id (obj/get child "$id")] (st/emit! (dwt/move-shapes-to-frame #{child-id} id nil nil) (ptk/data-event :layout/update {:ids [id]}))))) @@ -295,7 +295,6 @@ :else (st/emit! (dwsl/update-layout-child #{id} {:layout-item-v-sizing value})))))})) - (defn layout-child-proxy? [p] (obj/type-of? p "LayoutChildProxy")) diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index c409df8b16..5b434e9ceb 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -47,13 +47,13 @@ [app.main.data.workspace.variants :as dwv] [app.main.repo :as rp] [app.main.store :as st] + [app.plugins.flags :refer [natural-child-ordering?]] [app.plugins.flex :as flex] [app.plugins.format :as format] [app.plugins.grid :as grid] [app.plugins.parser :as parser] [app.plugins.register :as r] [app.plugins.ruler-guides :as rg] - [app.plugins.state :refer [natural-child-ordering?]] [app.plugins.text :as text] [app.plugins.utils :as u] [app.util.http :as http] @@ -960,9 +960,11 @@ (u/display-not-valid :appendChild "Plugin doesn't have 'content:write' permission") :else - (let [child-id (obj/get child "$id") + (let [child-id (obj/get child "$id") is-reversed? (ctl/flex-layout? shape) - index (if (and (natural-child-ordering? plugin-id) is-reversed?) 0 (count (:shapes shape)))] + index (if (and (natural-child-ordering? plugin-id) is-reversed?) + 0 + (count (:shapes shape)))] (st/emit! (dwsh/relocate-shapes #{child-id} id index)))))) :insertChild diff --git a/frontend/src/app/plugins/state.cljs b/frontend/src/app/plugins/state.cljs deleted file mode 100644 index 25c931571f..0000000000 --- a/frontend/src/app/plugins/state.cljs +++ /dev/null @@ -1,16 +0,0 @@ -;; 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.plugins.state - (:require - [app.main.store :as st])) - -(defn natural-child-ordering? - [plugin-id] - (boolean - (get-in - @st/state - [:workspace-local :plugin-flags plugin-id :natural-child-ordering]))) diff --git a/frontend/src/app/plugins/tokens.cljs b/frontend/src/app/plugins/tokens.cljs index dd4c18c592..268652e334 100644 --- a/frontend/src/app/plugins/tokens.cljs +++ b/frontend/src/app/plugins/tokens.cljs @@ -8,18 +8,17 @@ (:require [app.common.data.macros :as dm] [app.common.files.tokens :as cfo] + [app.common.json :as json] [app.common.schema :as sm] [app.common.types.token :as cto] [app.common.types.tokens-lib :as ctob] [app.common.uuid :as uuid] - [app.main.data.style-dictionary :as sd] [app.main.data.tokenscript :as ts] [app.main.data.workspace.tokens.application :as dwta] [app.main.data.workspace.tokens.library-edit :as dwtl] [app.main.store :as st] [app.plugins.utils :as u] [app.util.object :as obj] - [beicon.v2.core :as rx] [clojure.datafy :refer [datafy]])) ;; === Token @@ -87,7 +86,7 @@ :get (fn [_] (let [token (u/locate-token file-id set-id id)] - (:value token))) + (json/->js (:value token)))) :schema (let [token (u/locate-token file-id set-id id)] (cfo/make-token-value-schema (:type token))) :set @@ -260,20 +259,19 @@ :decode/options {:key-fn identity} :fn (fn [attrs] (let [tokens-lib (u/locate-tokens-lib file-id) - tokens-tree (ctob/get-tokens-in-active-sets tokens-lib) - token (ctob/make-token attrs)] - (->> (assoc tokens-tree (:name token) token) - (sd/resolve-tokens-interactive) - (rx/subs! - (fn [resolved-tokens] - (let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens (:name token))] - (if resolved-value - (st/emit! (dwtl/create-token id token)) - (u/display-not-valid :addToken (str errors))))))) - ;; TODO: as the addToken function is synchronous, we must return the newly created - ;; token even if the validator will throw it away if the resolution fails. - ;; This will be solved with the TokenScript resolver, that is syncronous. - (token-proxy plugin-id file-id id (:id token))))} + token (ctob/make-token attrs) + tokens-tree (-> (ctob/get-tokens-in-active-sets tokens-lib) + (assoc (:name token) token)) + resolved-tokens (ts/resolve-tokens tokens-tree) + + {:keys [errors resolved-value] :as resolved-token} + (get resolved-tokens (:name token))] + + (if resolved-value + (do (st/emit! (dwtl/create-token id token)) + (token-proxy plugin-id file-id id (:id token))) + (do (u/display-not-valid :addToken (str errors)) + nil))))} :duplicate (fn [] @@ -354,7 +352,17 @@ (st/emit! (dwtl/toggle-token-theme-active id))) :activeSets - {:this true :get (fn [_])} + {:this true + :get (fn [_] + (let [tokens-lib (u/locate-tokens-lib file-id) + theme (u/locate-token-theme file-id id)] + (->> theme + :sets + (map #(->> % + (ctob/get-set-by-name tokens-lib) + (ctob/get-id) + (token-set-proxy plugin-id file-id))) + (apply array))))} :addSet {:enumerable false diff --git a/plugins/apps/poc-tokens-plugin/src/app/app.component.html b/plugins/apps/poc-tokens-plugin/src/app/app.component.html index f5ef5ff940..9bb6fc8b9a 100644 --- a/plugins/apps/poc-tokens-plugin/src/app/app.component.html +++ b/plugins/apps/poc-tokens-plugin/src/app/app.component.html @@ -18,7 +18,12 @@