diff --git a/LICENSE b/LICENSE index e1c0b9705..a612ad981 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,6 @@ Mozilla Public License Version 2.0 ================================== - 1. Definitions -------------- diff --git a/common/src/app/common/files/changes_builder.cljc b/common/src/app/common/files/changes_builder.cljc index 0a74873bb..9da21cfda 100644 --- a/common/src/app/common/files/changes_builder.cljc +++ b/common/src/app/common/files/changes_builder.cljc @@ -401,7 +401,7 @@ (update :redo-changes conj add-change) (cond-> (and (ctk/in-component-copy? parent) (not ignore-touched)) - (update :undo-changes conj restore-touched-change)) + (update :undo-changes conj restore-touched-change)) (update :undo-changes conj del-change) (apply-changes-local))))) @@ -462,7 +462,7 @@ (update :redo-changes conj set-parent-change) (cond-> (ctk/in-component-copy? parent) - (update :undo-changes conj restore-touched-change)) + (update :undo-changes conj restore-touched-change)) (update :undo-changes #(reduce mk-undo-change % shapes)) (apply-changes-local))))) diff --git a/common/src/app/common/types/token.cljc b/common/src/app/common/types/token.cljc index 933f0da61..20be853b8 100644 --- a/common/src/app/common/types/token.cljc +++ b/common/src/app/common/types/token.cljc @@ -128,9 +128,9 @@ (sm/register! ::dimensions (merge-schemas ::sizing - ::spacing - ::stroke-width - ::border-radius)) + ::spacing + ::stroke-width + ::border-radius)) (def dimensions-keys (schema-keys ::dimensions)) @@ -145,8 +145,8 @@ (sm/register! ::applied-tokens (merge-schemas ::tokens - ::border-radius - ::sizing - ::spacing - ::rotation - ::dimensions)) + ::border-radius + ::sizing + ::spacing + ::rotation + ::dimensions)) diff --git a/frontend/dev/preload.cljs b/frontend/dev/preload.cljs deleted file mode 100644 index 57d3cc0d8..000000000 --- a/frontend/dev/preload.cljs +++ /dev/null @@ -1,7 +0,0 @@ -(ns preload - (:require - [devtools.core :as devtools])) - -;; Silence shadow-cljs devtools (ns reloading) -(devtools/set-pref! :dont-display-banner true) -(devtools/set-pref! :min-expandable-sequable-count-for-well-known-types 0) diff --git a/frontend/src/app/config.cljs b/frontend/src/app/config.cljs index 8ceacdbb5..e6b4361b0 100644 --- a/frontend/src/app/config.cljs +++ b/frontend/src/app/config.cljs @@ -63,11 +63,11 @@ :browser :webworker)) -(def default-flags ;;uncomment the below flags when Penpot Tokens Studio is ready to be merged into Penpot - [;;:enable-onboarding - ;;:enable-onboarding-team - ;;:enable-onboarding-questions - ;;:enable-onboarding-newsletter +(def default-flags + [:enable-onboarding + :enable-onboarding-team + :enable-onboarding-questions + :enable-onboarding-newsletter :enable-dashboard-templates-section :enable-google-fonts-provider :enable-component-thumbnails]) diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs index 3e3d8172b..17ce25d75 100644 --- a/frontend/src/app/main/ui.cljs +++ b/frontend/src/app/main/ui.cljs @@ -20,7 +20,6 @@ [app.main.ui.onboarding.team-choice :refer [onboarding-team-modal]] [app.main.ui.releases :refer [release-notes-modal]] [app.main.ui.static :as static] - [app.main.ui.workspace.tokens.modals.themes :as wtmt] [app.util.dom :as dom] [app.util.i18n :refer [tr]] [rumext.v2 :as mf])) diff --git a/frontend/src/app/main/ui/workspace/tokens/CHANGELOG.md b/frontend/src/app/main/ui/workspace/tokens/CHANGELOG.md deleted file mode 100644 index a55d4e1d1..000000000 --- a/frontend/src/app/main/ui/workspace/tokens/CHANGELOG.md +++ /dev/null @@ -1,114 +0,0 @@ -# Changelog - -Add changes that are meaningful to the user here after each PR so they can be updated in feature base. - -
-Template - -## Template - -### - - -[Link to PR]() - -If possible add video here from PR as well - -- Outline of changes -
- -## Changes - -### 2024-08-05 - Fix opacity updating - -[Link to PR](https://github.com/orgs/tokens-studio/projects/69/views/11?pane=issue&itemId=69801248) - -Fixes opacity not being applied correctly to shapes. - -### 2024-08-05 - Fix stroke witdth applying breaking app - -[Link to PR](https://github.com/orgs/tokens-studio/projects/69/views/11?pane=issue&itemId=73072870) - -`:stroke-width` token applying wont update for shapes without a stroke. - -### 2024-07-25 - UX Improvements for the context menu - -[Link to PR](https://github.com/tokens-studio/tokens-studio-for-penpot/pull/224) - -Changes context menu behavior according to [Specs](https://github.com/tokens-studio/obsidian-docs/blob/31f0d7f98ff5ac922970f3009fe877cc02d6d0cd/Products/TS%20for%20Penpot/Specs/Token%20State%20Specs.md) - -- Removing a token wont update the shape -- Mixed selection (shapes with applied, shapes without applied) will always unapply token -- Multi selection of shapes without token will apply the token to all -- Every shape change and token applying should be one undo step now -- Prevent token applying when nothign is selected -- `All` is a toggle instead of a checkbox if all tokens have been applied - - For instance with border radius the context menu can `:r1 :r2 :r3 :r4` which will highlight `All` - - If one attribute is missing it will check the single attributes - - Clicking a single attribute after clicking `All` will remove the other attributes -- Fixed some issues for switching between split and uniform border radius -- Clicking a token wont apply all attributes anymore. We apply only a select collection of attributes, which makes most sense. For instance on `sizing` we only apply `width` and `height` instead of all (`max-width`, `max-height`, `min-heigt`, `min-width`) - - -### 2024-07-05 - UX Improvements when applying tokens - -[Link to PR](https://github.com/tokens-studio/tokens-studio-for-penpot/compare/token-studio-develop...ux-improvements?body=&expand=1) - -- When unapplying tokens, the shape doesn't change anymore -- Multi Select behavior according to [Specs](https://github.com/tokens-studio/obsidian-docs/blob/31f0d7f98ff5ac922970f3009fe877cc02d6d0cd/Products/TS%20for%20Penpot/Specs/Token%20State%20Specs.md) -- Undo for applying tokens and change the shape is now one undo step - (before applying a token created multiple undo steps) - -[Video](https://github.com/tokens-studio/tokens-studio-for-penpot/assets/1898374/01d9d429-cab1-41cd-a3ff-495003edd3e8 -) - -### 2024-07-01 - Disallow creating tokens at existing paths - -Disallow creating tokens at an existing path. - -[Video](https://github.com/tokens-studio/tokens-studio-for-penpot/assets/1898374/557990fe-efe7-445b-8a1d-824396049db7 -) - -Example: -We've got a token with `borderRadius.sm`, so we can't allow to create a token at `borderRadius` or `borderRadius.sm`. -But we can allow creating a token at `borderRadius.md`. - - -### 2024-06-26 - Disallow special characters in token name - -- Only allows digits, letters and `-` as a part of a token name - -[Video](https://github.com/tokens-studio/tokens-studio-for-penpot/assets/1898374/7c59c0cc-d6e1-4b0d-9646-9a27eafcccc4 -) - -https://github.com/tokens-studio/tokens-studio-for-penpot/pull/200 - -### 2024-06-26 - Make Tokens JSON Export DTCG compatible - -![Screenshot of sample JSON Export in DTCG format](https://private-user-images.githubusercontent.com/9948167/343043570-b4bb39f7-ec53-409a-a053-b284d60848d9.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MTk0MDMyMzcsIm5iZiI6MTcxOTQwMjkzNywicGF0aCI6Ii85OTQ4MTY3LzM0MzA0MzU3MC1iNGJiMzlmNy1lYzUzLTQwOWEtYTA1My1iMjg0ZDYwODQ4ZDkucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDYyNiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA2MjZUMTE1NTM3WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MWEzZTU5OWQ0M2JkZWE5MTA5MDc4MTY1OTkyZWE5MmE5YzBlYmQ2NTcwMmEwZTdmMjViNGU5YTFjNWIxYjU5ZCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.qWJxRa_Y7LZ6EDJg5yPdOUIQkURFmZwMNec_BbdH9Co) - -https://github.com/tokens-studio/tokens-studio-for-penpot/issues/197 - -### 2024-06-25 - Token Insert/Edit Validation + Value Preview - -[Video](https://private-user-images.githubusercontent.com/1898374/342781533-06054a7e-3efb-4f48-a063-8b03f4b8fe5c.mp4?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MTkzMjgwNzYsIm5iZiI6MTcxOTMyNzc3NiwicGF0aCI6Ii8xODk4Mzc0LzM0Mjc4MTUzMy0wNjA1NGE3ZS0zZWZiLTRmNDgtYTA2My04YjAzZjRiOGZlNWMubXA0P1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDYyNSUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA2MjVUMTUwMjU2WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZDliZmUwMzU1MWY3NWQ2NWZkYzA0ODYxYzYzMTYzMjMyOGZjZGMzZDNhMWJmZGI4ZmM3NmU2NzNjYjY2MTdmMCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.44rKA1h3Cvw-vDWevnx7xVUeuZ1ezV4pqEtekVXgVds) - -https://github.com/tokens-studio/tokens-studio-for-penpot/pull/194 - -Adds validation to the token create/edit field - - - Name duplication is not allowed and takes a min/max length - - Value has to be a resolvable value - - Description has max value - -### 2024-06-24 - Added Ability to Export Tokens in JSON Format - -Sample JSON Output - https://github.com/user-attachments/files/15957831/tokens.json - -![JSON Export button Screenshot on the left Tokens Panel](https://private-user-images.githubusercontent.com/9948167/342395881-87ceaef0-79e5-4c6f-a25f-5130e47ed205.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MTk0MDQ2NzQsIm5iZiI6MTcxOTQwNDM3NCwicGF0aCI6Ii85OTQ4MTY3LzM0MjM5NTg4MS04N2NlYWVmMC03OWU1LTRjNmYtYTI1Zi01MTMwZTQ3ZWQyMDUucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDYyNiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA2MjZUMTIxOTM0WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZTg4NzAwZWFmNmM5ZDYzNDRmZjdlNWQzOTk3YjI4NTk4ODZiN2RiYTI1ODc0MDhmMzE3M2RkYTQwOGI2ZGU4NCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.LIjsIUutX72A_TtosO_I7f1z9v0nBo5brLl_BMOp-7Y) - -https://github.com/tokens-studio/tokens-studio-for-penpot/pull/191 - - -### 2024-06-19 - Added CHANGELOG.md - -Added template for changelog diff --git a/frontend/src/app/main/ui/workspace/tokens/form.cljs b/frontend/src/app/main/ui/workspace/tokens/form.cljs index f136926ab..6c9ea8fd5 100644 --- a/frontend/src/app/main/ui/workspace/tokens/form.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/form.cljs @@ -388,7 +388,7 @@ Token names should only contain letters and digits separated by . characters.")} :on-change on-update-value :ref value-input-ref} :render-right (when color? - (mf/fnc [] + (mf/fnc drop-down-button [] [:div {:class (stl/css :color-bullet) :on-click #(swap! color-ramp-open? not)} (if-let [hex (some-> @color tinycolor/valid-color tinycolor/->hex)] diff --git a/frontend/test/token_tests/helpers/state.cljs b/frontend/test/token_tests/helpers/state.cljs deleted file mode 100644 index fca9555c0..000000000 --- a/frontend/test/token_tests/helpers/state.cljs +++ /dev/null @@ -1,74 +0,0 @@ -(ns token-tests.helpers.state - (:require - [app.common.types.tokens-lib :as ctob] - [app.main.ui.workspace.tokens.style-dictionary :as sd] - [beicon.v2.core :as rx] - [potok.v2.core :as ptk])) - -(defn end - "Apply `attributes` that match `token` for `shape-ids`. - - Optionally remove attributes from `attributes-to-remove`, - this is useful for applying a single attribute from an attributes set - while removing other applied tokens from this set." - [] - (ptk/reify ::end - ptk/WatchEvent - (watch [_ _ _] - (rx/empty)))) - -(defn end+ - [] - (ptk/reify ::end+ - ptk/WatchEvent - (watch [_ state _] - (->> (rx/from (-> (get-in state [:workspace-data :tokens-lib]) - (ctob/get-active-themes-set-tokens) - (sd/resolve-tokens+))) - (rx/mapcat #(rx/of (end))))))) - -(defn stop-on - "Helper function to be used with async version of run-store. - - Will stop the execution after event with `event-type` has completed." - [event-type] - (fn [stream] - (->> stream - #_(rx/tap #(prn (ptk/type %))) - (rx/filter #(ptk/type? event-type %))))) - -(def stop-on-send-update-indices - "Stops on `send-update-indices` function being called, which should be the last function of an event chain." - (stop-on ::end)) - -;; Support for async events in tests -;; https://chat.kaleidos.net/penpot-partners/pl/tz1yoes3w3fr9qanxqpuhoz3ch -(defn run-store - "Async version of `frontend-tests.helpers.state/run-store`." - ([store done events completed-cb] - (run-store store done events completed-cb nil)) - ([store done events completed-cb stopper] - (let [stream (ptk/input-stream store) - stopper-s (if (fn? stopper) - (stopper stream) - (rx/filter #(= :the/end %) stream))] - (->> stream - (rx/take-until stopper-s) - (rx/last) - (rx/tap (fn [_] - (completed-cb @store))) - (rx/subs! (fn [_] (done)) - (fn [cause] - (js/console.log "[error]:" cause)) - (fn [_] - #_(js/console.log "[complete]")))) - (doseq [event (concat events [(end+)])] - (ptk/emit! store event)) - (ptk/emit! store :the/end)))) - -(defn run-store-async - "Helper version of `run-store` that automatically stops on the `send-update-indices` event" - ([store done events completed-cb] - (run-store store done events completed-cb stop-on-send-update-indices)) - ([store done events completed-cb stop-on] - (run-store store done events completed-cb stop-on))) diff --git a/frontend/test/token_tests/helpers/tokens.cljs b/frontend/test/token_tests/helpers/tokens.cljs deleted file mode 100644 index 4f510c002..000000000 --- a/frontend/test/token_tests/helpers/tokens.cljs +++ /dev/null @@ -1,26 +0,0 @@ -(ns token-tests.helpers.tokens - (:require - [app.common.test-helpers.ids-map :as thi] - [app.common.types.tokens-lib :as ctob] - [app.main.ui.workspace.tokens.token :as wtt])) - -(defn add-token [state label params] - (let [id (thi/new-id! label) - token (assoc params :id id)] - (update-in state [:data :tokens] assoc id token))) - -(defn get-token [file name] - (some-> (get-in file [:data :tokens-lib]) - (ctob/get-active-themes-set-tokens) - (get name))) - -(defn apply-token-to-shape [file shape-label token-label attributes] - (let [first-page-id (get-in file [:data :pages 0]) - shape-id (thi/id shape-label) - token (get-token file token-label) - applied-attributes (wtt/attributes-map attributes token)] - (update-in file [:data - :pages-index first-page-id - :objects shape-id - :applied-tokens] - merge applied-attributes))) diff --git a/frontend/test/token_tests/logic/token_actions_test.cljs b/frontend/test/token_tests/logic/token_actions_test.cljs deleted file mode 100644 index e3f215c03..000000000 --- a/frontend/test/token_tests/logic/token_actions_test.cljs +++ /dev/null @@ -1,407 +0,0 @@ -(ns token-tests.logic.token-actions-test - (:require - [app.common.logging :as log] - [app.common.test-helpers.compositions :as ctho] - [app.common.test-helpers.files :as cthf] - [app.common.test-helpers.shapes :as cths] - [app.common.types.tokens-lib :as ctob] - [app.main.ui.workspace.tokens.changes :as wtch] - [app.main.ui.workspace.tokens.token :as wtt] - [cljs.test :as t :include-macros true] - [frontend-tests.helpers.pages :as thp] - [frontend-tests.helpers.state :as ths] - [token-tests.helpers.state :as tohs] - [token-tests.helpers.tokens :as toht])) - -(t/use-fixtures :each - {:before (fn [] - ;; Ignore rxjs async errors - (log/set-level! "app.main.data.changes" :error) - (thp/reset-idmap!))}) - -(defn setup-file [] - (cthf/sample-file :file-1 :page-label :page-1)) - -(def border-radius-token - {:name "borderRadius.sm" - :value "12" - :type :border-radius}) - -(def reference-border-radius-token - {:name "borderRadius.md" - :value "{borderRadius.sm} * 2" - :type :border-radius}) - -(defn setup-file-with-tokens - [& {:keys [rect-1 rect-2 rect-3]}] - (-> (setup-file) - (ctho/add-rect :rect-1 rect-1) - (ctho/add-rect :rect-2 rect-2) - (ctho/add-rect :rect-3 rect-3) - (assoc-in [:data :tokens-lib] - (-> (ctob/make-tokens-lib) - (ctob/add-theme (ctob/make-token-theme :name "Theme A" :sets #{"Set A"})) - (ctob/set-active-themes #{"/Theme A"}) - (ctob/add-set (ctob/make-token-set :name "Set A")) - (ctob/add-token-in-set "Set A" (ctob/make-token border-radius-token)) - (ctob/add-token-in-set "Set A" (ctob/make-token reference-border-radius-token)))))) - -(t/deftest test-apply-token - (t/testing "applies token to shape and updates shape attributes to resolved value" - (t/async - done - (let [file (setup-file-with-tokens) - store (ths/setup-store file) - rect-1 (cths/get-shape file :rect-1) - events [(wtch/apply-token {:shape-ids [(:id rect-1)] - :attributes #{:rx :ry} - :token (toht/get-token file "borderRadius.md") - :on-update-shape wtch/update-shape-radius-all})]] - (tohs/run-store-async - store done events - (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - token (toht/get-token file' "borderRadius.md") - rect-1' (cths/get-shape file' :rect-1)] - (t/testing "shape `:applied-tokens` got updated" - (t/is (some? (:applied-tokens rect-1'))) - (t/is (= (:rx (:applied-tokens rect-1')) (:name token))) - (t/is (= (:ry (:applied-tokens rect-1')) (:name token)))) - (t/testing "shape radius got update to the resolved token value." - (t/is (= (:rx rect-1') 24)) - (t/is (= (:ry rect-1') 24)))))))))) - -(t/deftest test-apply-multiple-tokens - (t/testing "applying a token twice with the same attributes will override the previously applied tokens values" - (t/async - done - (let [file (setup-file-with-tokens) - store (ths/setup-store file) - rect-1 (cths/get-shape file :rect-1) - events [(wtch/apply-token {:shape-ids [(:id rect-1)] - :attributes #{:rx :ry} - :token (toht/get-token file "borderRadius.sm") - :on-update-shape wtch/update-shape-radius-all}) - (wtch/apply-token {:shape-ids [(:id rect-1)] - :attributes #{:rx :ry} - :token (toht/get-token file "borderRadius.md") - :on-update-shape wtch/update-shape-radius-all})]] - (tohs/run-store-async - store done events - (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - token (toht/get-token file' "borderRadius.md") - rect-1' (cths/get-shape file' :rect-1)] - (t/testing "shape `:applied-tokens` got updated" - (t/is (some? (:applied-tokens rect-1'))) - (t/is (= (:rx (:applied-tokens rect-1')) (:name token))) - (t/is (= (:ry (:applied-tokens rect-1')) (:name token)))) - (t/testing "shape radius got update to the resolved token value." - (t/is (= (:rx rect-1') 24)) - (t/is (= (:ry rect-1') 24)))))))))) - -(t/deftest test-apply-token-overwrite - (t/testing "removes old token attributes and applies only single attribute" - (t/async - done - (let [file (setup-file-with-tokens) - store (ths/setup-store file) - rect-1 (cths/get-shape file :rect-1) - events [;; Apply "borderRadius.sm" to all border radius attributes - (wtch/apply-token {:attributes #{:rx :ry :r1 :r2 :r3 :r4} - :token (toht/get-token file "borderRadius.sm") - :shape-ids [(:id rect-1)] - :on-update-shape wtch/update-shape-radius-all}) - ;; Apply single `:r1` attribute to same shape - ;; while removing other attributes from the border-radius set - ;; but keep `:r4` for testing purposes - (wtch/apply-token {:attributes #{:r1} - :attributes-to-remove #{:rx :ry :r1 :r2 :r3} - :token (toht/get-token file "borderRadius.md") - :shape-ids [(:id rect-1)] - :on-update-shape wtch/update-shape-radius-all})]] - (tohs/run-store-async - store done events - (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - token-sm (toht/get-token file' "borderRadius.sm") - token-md (toht/get-token file' "borderRadius.md") - rect-1' (cths/get-shape file' :rect-1)] - (t/testing "other border-radius attributes got removed" - (t/is (nil? (:rx (:applied-tokens rect-1'))))) - (t/testing "r1 got applied with borderRadius.md" - (t/is (= (:r1 (:applied-tokens rect-1')) (:name token-md)))) - (t/testing "while :r4 was kept with borderRadius.sm" - (t/is (= (:r4 (:applied-tokens rect-1')) (:name token-sm))))))))))) - -(t/deftest test-apply-dimensions - (t/testing "applies dimensions token and updates the shapes width and height" - (t/async - done - (let [dimensions-token {:name "dimensions.sm" - :value "100" - :type :dimensions} - file (-> (setup-file-with-tokens) - (update-in [:data :tokens-lib] - #(ctob/add-token-in-set % "Set A" (ctob/make-token dimensions-token)))) - store (ths/setup-store file) - rect-1 (cths/get-shape file :rect-1) - events [(wtch/apply-token {:shape-ids [(:id rect-1)] - :attributes #{:width :height} - :token (toht/get-token file "dimensions.sm") - :on-update-shape wtch/update-shape-dimensions})]] - (tohs/run-store-async - store done events - (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - token-target' (toht/get-token file' "dimensions.sm") - rect-1' (cths/get-shape file' :rect-1)] - (t/testing "shape `:applied-tokens` got updated" - (t/is (some? (:applied-tokens rect-1'))) - (t/is (= (:width (:applied-tokens rect-1')) (:name token-target'))) - (t/is (= (:height (:applied-tokens rect-1')) (:name token-target')))) - (t/testing "shapes width and height got updated" - (t/is (= (:width rect-1') 100)) - (t/is (= (:height rect-1') 100)))))))))) - -(t/deftest test-apply-sizing - (t/testing "applies sizing token and updates the shapes width and height" - (t/async - done - (let [sizing-token {:name "sizing.sm" - :value "100" - :type :sizing} - file (-> (setup-file-with-tokens) - (update-in [:data :tokens-lib] - #(ctob/add-token-in-set % "Set A" (ctob/make-token sizing-token)))) - store (ths/setup-store file) - rect-1 (cths/get-shape file :rect-1) - events [(wtch/apply-token {:shape-ids [(:id rect-1)] - :attributes #{:width :height} - :token (toht/get-token file "sizing.sm") - :on-update-shape wtch/update-shape-dimensions})]] - (tohs/run-store-async - store done events - (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - token-target' (toht/get-token file' "sizing.sm") - rect-1' (cths/get-shape file' :rect-1)] - (t/testing "shape `:applied-tokens` got updated" - (t/is (some? (:applied-tokens rect-1'))) - (t/is (= (:width (:applied-tokens rect-1')) (:name token-target'))) - (t/is (= (:height (:applied-tokens rect-1')) (:name token-target')))) - (t/testing "shapes width and height got updated" - (t/is (= (:width rect-1') 100)) - (t/is (= (:height rect-1') 100)))))))))) - -(t/deftest test-apply-opacity - (t/testing "applies opacity token and updates the shapes opacity" - (t/async - done - (let [opacity-float {:name "opacity.float" - :value "0.3" - :type :opacity} - opacity-percent {:name "opacity.percent" - :value "40%" - :type :opacity} - opacity-invalid {:name "opacity.invalid" - :value "100" - :type :opacity} - file (-> (setup-file-with-tokens) - (update-in [:data :tokens-lib] - #(-> % - (ctob/add-token-in-set "Set A" (ctob/make-token opacity-float)) - (ctob/add-token-in-set "Set A" (ctob/make-token opacity-percent)) - (ctob/add-token-in-set "Set A" (ctob/make-token opacity-invalid))))) - store (ths/setup-store file) - rect-1 (cths/get-shape file :rect-1) - rect-2 (cths/get-shape file :rect-2) - rect-3 (cths/get-shape file :rect-3) - events [(wtch/apply-token {:shape-ids [(:id rect-1)] - :attributes #{:opacity} - :token (toht/get-token file "opacity.float") - :on-update-shape wtch/update-opacity}) - (wtch/apply-token {:shape-ids [(:id rect-2)] - :attributes #{:opacity} - :token (toht/get-token file "opacity.percent") - :on-update-shape wtch/update-opacity}) - (wtch/apply-token {:shape-ids [(:id rect-3)] - :attributes #{:opacity} - :token (toht/get-token file "opacity.invalid") - :on-update-shape wtch/update-opacity})]] - (tohs/run-store-async - store done events - (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - rect-1' (cths/get-shape file' :rect-1) - rect-2' (cths/get-shape file' :rect-2) - rect-3' (cths/get-shape file' :rect-3) - token-opacity-float (toht/get-token file' "opacity.float") - token-opacity-percent (toht/get-token file' "opacity.percent") - token-opacity-invalid (toht/get-token file' "opacity.invalid")] - (t/testing "float value got translated to float and applied to opacity" - (t/is (= (:opacity (:applied-tokens rect-1')) (:name token-opacity-float))) - (t/is (= (:opacity rect-1') 0.3))) - (t/testing "percentage value got translated to float and applied to opacity" - (t/is (= (:opacity (:applied-tokens rect-2')) (:name token-opacity-percent))) - (t/is (= (:opacity rect-2') 0.4))) - (t/testing "invalid opacity value got applied but did not change shape" - (t/is (= (:opacity (:applied-tokens rect-3')) (:name token-opacity-invalid))) - (t/is (nil? (:opacity rect-3'))))))))))) - -(t/deftest test-apply-rotation - (t/testing "applies rotation token and updates the shapes rotation" - (t/async - done - (let [rotation-token {:name "rotation.medium" - :value "120" - :type :rotation} - file (-> (setup-file-with-tokens) - (update-in [:data :tokens-lib] - #(ctob/add-token-in-set % "Set A" (ctob/make-token rotation-token)))) - store (ths/setup-store file) - rect-1 (cths/get-shape file :rect-1) - events [(wtch/apply-token {:shape-ids [(:id rect-1)] - :attributes #{:rotation} - :token (toht/get-token file "rotation.medium") - :on-update-shape wtch/update-rotation})]] - (tohs/run-store-async - store done events - (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - token-target' (toht/get-token file' "rotation.medium") - rect-1' (cths/get-shape file' :rect-1)] - (t/is (some? (:applied-tokens rect-1'))) - (t/is (= (:rotation (:applied-tokens rect-1')) (:name token-target'))) - (t/is (= (:rotation rect-1') 120))))))))) - -(t/deftest test-apply-stroke-width - (t/testing "applies stroke-width token and updates the shapes with stroke" - (t/async - done - (let [stroke-width-token {:name "stroke-width.sm" - :value "10" - :type :stroke-width} - file (-> (setup-file-with-tokens {:rect-1 {:strokes [{:stroke-alignment :inner, - :stroke-style :solid, - :stroke-color "#000000", - :stroke-opacity 1, - :stroke-width 5}]}}) - (update-in [:data :tokens-lib] - #(ctob/add-token-in-set % "Set A" (ctob/make-token stroke-width-token)))) - store (ths/setup-store file) - rect-with-stroke (cths/get-shape file :rect-1) - rect-without-stroke (cths/get-shape file :rect-2) - events [(wtch/apply-token {:shape-ids [(:id rect-with-stroke) (:id rect-without-stroke)] - :attributes #{:stroke-width} - :token (toht/get-token file "stroke-width.sm") - :on-update-shape wtch/update-stroke-width})]] - (tohs/run-store-async - store done events - (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - token-target' (toht/get-token file' "stroke-width.sm") - rect-with-stroke' (cths/get-shape file' :rect-1) - rect-without-stroke' (cths/get-shape file' :rect-2)] - (t/testing "token got applied to rect with stroke and shape stroke got updated" - (t/is (= (:stroke-width (:applied-tokens rect-with-stroke')) (:name token-target'))) - (t/is (= (get-in rect-with-stroke' [:strokes 0 :stroke-width]) 10))) - (t/testing "token got applied to rect without stroke but shape didnt get updated" - (t/is (= (:stroke-width (:applied-tokens rect-without-stroke')) (:name token-target'))) - (t/is (empty? (:strokes rect-without-stroke'))))))))))) - -(t/deftest test-toggle-token-none - (t/testing "should apply token to all selected items, where no item has the token applied" - (t/async - done - (let [file (setup-file-with-tokens) - store (ths/setup-store file) - rect-1 (cths/get-shape file :rect-1) - rect-2 (cths/get-shape file :rect-2) - events [(wtch/toggle-token {:shapes [rect-1 rect-2] - :token-type-props {:attributes #{:rx :ry} - :on-update-shape wtch/update-shape-radius-all} - :token (toht/get-token file "borderRadius.md")})]] - (tohs/run-store-async - store done events - (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - token-2' (toht/get-token file' "borderRadius.md") - rect-1' (cths/get-shape file' :rect-1) - rect-2' (cths/get-shape file' :rect-2)] - (t/is (some? (:applied-tokens rect-1'))) - (t/is (some? (:applied-tokens rect-2'))) - (t/is (= (:rx (:applied-tokens rect-1')) (:name token-2'))) - (t/is (= (:rx (:applied-tokens rect-2')) (:name token-2'))) - (t/is (= (:ry (:applied-tokens rect-1')) (:name token-2'))) - (t/is (= (:ry (:applied-tokens rect-2')) (:name token-2'))) - (t/is (= (:rx rect-1') 24)) - (t/is (= (:rx rect-2') 24))))))))) - -(t/deftest test-toggle-token-mixed - (t/testing "should unapply given token if one of the selected items has the token applied while keeping other tokens with some attributes" - (t/async - done - (let [file (-> (setup-file-with-tokens) - (toht/apply-token-to-shape :rect-1 "borderRadius.sm" #{:rx :ry}) - (toht/apply-token-to-shape :rect-3 "borderRadius.md" #{:rx :ry})) - store (ths/setup-store file) - - rect-with-token (cths/get-shape file :rect-1) - rect-without-token (cths/get-shape file :rect-2) - rect-with-other-token (cths/get-shape file :rect-3) - - events [(wtch/toggle-token {:shapes [rect-with-token rect-without-token rect-with-other-token] - :token (toht/get-token file "borderRadius.sm") - :token-type-props {:attributes #{:rx :ry}}})]] - (tohs/run-store-async - store done events - (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - rect-with-token' (cths/get-shape file' :rect-1) - rect-without-token' (cths/get-shape file' :rect-2) - rect-with-other-token' (cths/get-shape file' :rect-3)] - - (t/testing "rect-with-token got the token removed" - (t/is (nil? (:rx (:applied-tokens rect-with-token')))) - (t/is (nil? (:ry (:applied-tokens rect-with-token'))))) - - (t/testing "rect-without-token didn't get updated" - (t/is (= (:applied-tokens rect-without-token') (:applied-tokens rect-without-token)))) - - (t/testing "rect-with-other-token didn't get updated" - (t/is (= (:applied-tokens rect-with-other-token') (:applied-tokens rect-with-other-token))))))))))) - -(t/deftest test-toggle-token-apply-to-all - (t/testing "should apply token to all if none of the shapes has it applied" - (t/async - done - (let [file (-> (setup-file-with-tokens) - (toht/apply-token-to-shape :rect-1 "borderRadius.md" #{:rx :ry}) - (toht/apply-token-to-shape :rect-3 "borderRadius.md" #{:rx :ry})) - store (ths/setup-store file) - - rect-with-other-token-1 (cths/get-shape file :rect-1) - rect-without-token (cths/get-shape file :rect-2) - rect-with-other-token-2 (cths/get-shape file :rect-3) - - events [(wtch/toggle-token {:shapes [rect-with-other-token-1 rect-without-token rect-with-other-token-2] - :token (toht/get-token file "borderRadius.sm") - :token-type-props {:attributes #{:rx :ry}}})]] - (tohs/run-store-async - store done events - (fn [new-state] - (let [file' (ths/get-file-from-store new-state) - target-token (toht/get-token file' "borderRadius.sm") - rect-with-other-token-1' (cths/get-shape file' :rect-1) - rect-without-token' (cths/get-shape file' :rect-2) - rect-with-other-token-2' (cths/get-shape file' :rect-3)] - - (t/testing "token got applied to all shapes" - (t/is (= (:rx (:applied-tokens rect-with-other-token-1')) (:name target-token))) - (t/is (= (:rx (:applied-tokens rect-without-token')) (:name target-token))) - (t/is (= (:rx (:applied-tokens rect-with-other-token-2')) (:name target-token))) - - (t/is (= (:ry (:applied-tokens rect-with-other-token-1')) (:name target-token))) - (t/is (= (:ry (:applied-tokens rect-without-token')) (:name target-token))) - (t/is (= (:ry (:applied-tokens rect-with-other-token-2')) (:name target-token))))))))))) diff --git a/frontend/test/token_tests/style_dictionary_test.cljs b/frontend/test/token_tests/style_dictionary_test.cljs deleted file mode 100644 index 519b1f09e..000000000 --- a/frontend/test/token_tests/style_dictionary_test.cljs +++ /dev/null @@ -1,115 +0,0 @@ -(ns token-tests.style-dictionary-test - (:require - [app.common.transit :as tr] - [app.common.types.tokens-lib :as ctob] - [app.main.ui.workspace.tokens.style-dictionary :as sd] - [beicon.v2.core :as rx] - [cljs.test :as t :include-macros true] - [promesa.core :as p])) - -(t/deftest resolve-tokens-test - (t/async - done - (t/testing "resolves tokens using style-dictionary from a ids map" - (let [tokens (-> (ctob/make-tokens-lib) - (ctob/add-set (ctob/make-token-set :name "core")) - (ctob/add-token-in-set "core" (ctob/make-token {:name "borderRadius.sm" - :value "12px" - :type :border-radius})) - (ctob/add-token-in-set "core" (ctob/make-token {:value "{borderRadius.sm} * 2" - :name "borderRadius.md-with-dashes" - :type :border-radius})) - (ctob/get-all-tokens))] - (-> (sd/resolve-tokens+ tokens) - (p/finally - (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-with-dashes" :resolved-value]))) - (t/is (= "px" (get-in resolved-tokens ["borderRadius.md-with-dashes" :unit]))) - (done)))))))) - -(t/deftest process-json-stream-test - (t/async - done - (t/testing "processes empty json string" - (let [json (-> {"core" {"color" {"$value" "red" - "$type" "color"}}} - (tr/encode-str {:type :json-verbose}))] - (->> (rx/of json) - (sd/process-json-stream) - (rx/subs! (fn [tokens-lib] - (t/is (instance? ctob/TokensLib tokens-lib)) - (t/is (= "red" (-> (ctob/get-set tokens-lib "core") - (ctob/get-token "color") - (:value)))) - (done)))))))) - -(t/deftest reference-errros-test - (t/testing "Extracts reference errors from StyleDictionary errors" - ;; Using unicode for the white-space after "Error: " as some editors might remove it and its more visible - (t/is (= - ["Some token references (2) could not be found." - "" - "foo.value tries to reference missing, which is not defined." - "color.value tries to reference missing, which is not defined."] - (sd/reference-errors "Error:\u0020 -Reference Errors: -Some token references (2) could not be found. - -foo.value tries to reference missing, which is not defined. -color.value tries to reference missing, which is not defined."))) - (t/is (nil? (sd/reference-errors nil))) - (t/is (nil? (sd/reference-errors "none"))))) - -(t/deftest process-empty-json-stream-test - (t/async - done - (t/testing "processes empty json string" - (->> (rx/of "{}") - (sd/process-json-stream) - (rx/subs! (fn [tokens-lib] - (t/is (instance? ctob/TokensLib tokens-lib)) - (done))))))) - -(t/deftest process-invalid-json-stream-test - (t/async - done - (t/testing "fails on invalid json" - (->> (rx/of "{,}") - (sd/process-json-stream) - (rx/subs! - (fn [] - (throw (js/Error. "Should be an error"))) - (fn [err] - (t/is (= :error.import/json-parse-error (:error/code (ex-data err)))) - (done))))))) - -(t/deftest process-non-token-json-stream-test - (t/async - done - (t/testing "fails on non-token json" - (->> (rx/of "{\"foo\": \"bar\"}") - (sd/process-json-stream) - (rx/subs! - (fn [] - (throw (js/Error. "Should be an error"))) - (fn [err] - (t/is (= :error.import/invalid-json-data (:error/code (ex-data err)))) - (done))))))) - -(t/deftest process-missing-references-json-test - (t/async - done - (t/testing "fails on missing references in tokens" - (let [json (-> {"core" {"color" {"$value" "{missing}" - "$type" "color"}}} - (tr/encode-str {:type :json-verbose}))] - (->> (rx/of json) - (sd/process-json-stream) - (rx/subs! - (fn [] - (throw (js/Error. "Should be an error"))) - (fn [err] - (t/is (= :error.import/style-dictionary-reference-errors (:error/code (ex-data err)))) - (done)))))))) diff --git a/frontend/test/token_tests/token_form_test.cljs b/frontend/test/token_tests/token_form_test.cljs deleted file mode 100644 index 2bc14df32..000000000 --- a/frontend/test/token_tests/token_form_test.cljs +++ /dev/null @@ -1,26 +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 token-tests.token-form-test - (:require - [app.main.ui.workspace.tokens.form :as wtf] - [cljs.test :as t :include-macros true] - [malli.core :as m])) - -(t/deftest test-valid-token-name-schema - ;; Allow regular namespace token names - (t/is (some? (m/validate wtf/valid-token-name-schema "Foo"))) - (t/is (some? (m/validate wtf/valid-token-name-schema "foo"))) - (t/is (some? (m/validate wtf/valid-token-name-schema "FOO"))) - (t/is (some? (m/validate wtf/valid-token-name-schema "Foo.Bar.Baz"))) - ;; Allow trailing tokens - (t/is (nil? (m/validate wtf/valid-token-name-schema "Foo.Bar.Baz...."))) - ;; Disallow multiple separator dots - (t/is (nil? (m/validate wtf/valid-token-name-schema "Foo..Bar.Baz"))) - ;; Disallow any special characters - (t/is (nil? (m/validate wtf/valid-token-name-schema "Hey Foo.Bar"))) - (t/is (nil? (m/validate wtf/valid-token-name-schema "Hey😈Foo.Bar"))) - (t/is (nil? (m/validate wtf/valid-token-name-schema "Hey%Foo.Bar")))) diff --git a/frontend/test/token_tests/token_test.cljs b/frontend/test/token_tests/token_test.cljs deleted file mode 100644 index 309fed6e2..000000000 --- a/frontend/test/token_tests/token_test.cljs +++ /dev/null @@ -1,100 +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 token-tests.token-test - (:require - [app.main.ui.workspace.tokens.token :as wtt] - [cljs.test :as t :include-macros true])) - -(t/deftest test-parse-token-value - (t/testing "parses double from a token value" - (t/is (= {:value 100.1 :unit nil} (wtt/parse-token-value "100.1"))) - (t/is (= {:value -9 :unit nil} (wtt/parse-token-value "-9")))) - (t/testing "trims white-space" - (t/is (= {:value -1.3 :unit nil} (wtt/parse-token-value " -1.3 ")))) - (t/testing "parses unit: px" - (t/is (= {:value 70.3 :unit "px"} (wtt/parse-token-value " 70.3px ")))) - (t/testing "parses unit: %" - (t/is (= {:value -10 :unit "%"} (wtt/parse-token-value "-10%")))) - (t/testing "parses unit: px") - (t/testing "returns nil for any invalid characters" - (t/is (nil? (wtt/parse-token-value " -1.3a ")))) - (t/testing "doesnt accept invalid double" - (t/is (nil? (wtt/parse-token-value ".3"))))) - -(t/deftest remove-attributes-for-token-id - (t/testing "removes attributes matching the `token`, keeps other attributes" - (t/is (= {:ry "b"} - (wtt/remove-attributes-for-token #{:rx :ry} {:name "a"} {:rx "a" :ry "b"}))))) - -(t/deftest token-applied-test - (t/testing "matches passed token with `:token-attributes`" - (t/is (true? (wtt/token-applied? {:name "a"} {:applied-tokens {:x "a"}} #{:x})))) - (t/testing "doesn't match empty token" - (t/is (nil? (wtt/token-applied? {} {:applied-tokens {:x "a"}} #{:x})))) - (t/testing "does't match passed token `:id`" - (t/is (nil? (wtt/token-applied? {:name "b"} {:applied-tokens {:x "a"}} #{:x})))) - (t/testing "doesn't match passed `:token-attributes`" - (t/is (nil? (wtt/token-applied? {:name "a"} {:applied-tokens {:x "a"}} #{:y}))))) - -(t/deftest shapes-ids-by-applied-attributes - (t/testing "Returns set of matched attributes that fit the applied token" - (let [attributes #{:x :y :z} - shape-applied-x {:id "shape-applied-x" - :applied-tokens {:x "1"}} - shape-applied-y {:id "shape-applied-y" - :applied-tokens {:y "1"}} - shape-applied-x-y {:id "shape-applied-x-y" - :applied-tokens {:x "1" :y "1"}} - shape-applied-none {:id "shape-applied-none" - :applied-tokens {}} - shape-applied-all {:id "shape-applied-all" - :applied-tokens {:x "1" :y "1" :z "1"}} - shape-ids (fn [& xs] (into #{} (map :id xs))) - shapes [shape-applied-x - shape-applied-y - shape-applied-x-y - shape-applied-all - shape-applied-none] - expected (wtt/shapes-ids-by-applied-attributes {:name "1"} shapes attributes)] - (t/is (= (:x expected) (shape-ids shape-applied-x - shape-applied-x-y - shape-applied-all))) - (t/is (= (:y expected) (shape-ids shape-applied-y - shape-applied-x-y - shape-applied-all))) - (t/is (= (:z expected) (shape-ids shape-applied-all))) - (t/is (true? (wtt/shapes-applied-all? expected (shape-ids shape-applied-all) attributes))) - (t/is (false? (wtt/shapes-applied-all? expected (apply shape-ids shapes) attributes))) - (shape-ids shape-applied-x - shape-applied-x-y - shape-applied-all)))) - -(t/deftest tokens-applied-test - (t/testing "is true when single shape matches the token and attributes" - (t/is (true? (wtt/shapes-token-applied? {:name "a"} [{:applied-tokens {:x "a"}} - {:applied-tokens {:x "b"}}] - #{:x})))) - (t/testing "is false when no shape matches the token or attributes" - (t/is (nil? (wtt/shapes-token-applied? {:name "a"} [{:applied-tokens {:x "b"}} - {:applied-tokens {:x "b"}}] - #{:x}))) - (t/is (nil? (wtt/shapes-token-applied? {:name "a"} [{:applied-tokens {:x "a"}} - {:applied-tokens {:x "a"}}] - #{:y}))))) - -(t/deftest name->path-test - (t/is (= ["foo" "bar" "baz"] (wtt/token-name->path "foo.bar.baz"))) - (t/is (= ["foo" "bar" "baz"] (wtt/token-name->path "foo..bar.baz"))) - (t/is (= ["foo" "bar" "baz"] (wtt/token-name->path "foo..bar.baz....")))) - -(t/deftest token-name-path-exists?-test - (t/is (true? (wtt/token-name-path-exists? "border-radius" {"border-radius" {"sm" {:name "sm"}}}))) - (t/is (true? (wtt/token-name-path-exists? "border-radius" {"border-radius" {:name "sm"}}))) - (t/is (true? (wtt/token-name-path-exists? "border-radius.sm" {"border-radius" {:name "sm"}}))) - (t/is (true? (wtt/token-name-path-exists? "border-radius.sm.x" {"border-radius" {:name "sm"}}))) - (t/is (false? (wtt/token-name-path-exists? "other" {"border-radius" {:name "sm"}}))) - (t/is (false? (wtt/token-name-path-exists? "dark.border-radius.md" {"dark" {"border-radius" {"sm" {:name "sm"}}}}))))