mirror of
https://github.com/penpot/penpot.git
synced 2025-01-20 13:42:59 -05:00
🎉 Automatically unapply tokens when user changes attr values
This commit is contained in:
parent
05ec84ca1b
commit
edfa80d5b1
5 changed files with 243 additions and 13 deletions
|
@ -14,8 +14,33 @@
|
|||
[app.common.types.container :as ctn]
|
||||
[app.common.types.shape.interactions :as ctsi]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.uuid :as uuid]))
|
||||
|
||||
(defn- check-unapply-tokens
|
||||
[changes objects]
|
||||
(let [mod-obj-changes (->> (:redo-changes changes)
|
||||
(filter #(= (:type %) :mod-obj)))
|
||||
|
||||
check-attr (fn [shape changes attr]
|
||||
(let [tokens (get shape :applied-tokens {})
|
||||
token-attrs (cto/shape-attr->token-attrs attr)]
|
||||
(if (some #(contains? tokens %) token-attrs)
|
||||
(pcb/update-shapes changes [(:id shape)] #(cto/unapply-token-id % token-attrs))
|
||||
changes)))
|
||||
|
||||
check-shape (fn [changes mod-obj-change]
|
||||
(let [shape (get objects (:id mod-obj-change))
|
||||
xf (comp (filter #(= (:type %) :set))
|
||||
(map :attr))
|
||||
attrs (into [] xf (:operations mod-obj-change))]
|
||||
(reduce (partial check-attr shape)
|
||||
changes
|
||||
attrs)))]
|
||||
(reduce check-shape
|
||||
changes
|
||||
mod-obj-changes)))
|
||||
|
||||
(defn generate-update-shapes
|
||||
[changes ids update-fn objects {:keys [attrs ignore-tree ignore-touched with-objects?]}]
|
||||
(let [changes (reduce
|
||||
|
@ -29,8 +54,12 @@
|
|||
(pcb/with-objects objects))
|
||||
ids)
|
||||
grid-ids (->> ids (filter (partial ctl/grid-layout? objects)))
|
||||
changes (pcb/update-shapes changes grid-ids ctl/assign-cell-positions {:with-objects? true})
|
||||
changes (pcb/reorder-grid-children changes ids)]
|
||||
changes (-> changes
|
||||
(pcb/update-shapes grid-ids ctl/assign-cell-positions {:with-objects? true})
|
||||
(pcb/reorder-grid-children ids)
|
||||
(cond->
|
||||
(not ignore-touched)
|
||||
(check-unapply-tokens objects)))]
|
||||
changes))
|
||||
|
||||
(defn- generate-update-shape-flags
|
||||
|
|
|
@ -23,6 +23,14 @@
|
|||
[file f]
|
||||
(ctf/update-file-data file #(update % :tokens-lib f)))
|
||||
|
||||
(defn get-token
|
||||
[file set-name token-name]
|
||||
(let [tokens-lib (:tokens-lib (:data file))]
|
||||
(when tokens-lib
|
||||
(-> tokens-lib
|
||||
(ctob/get-set set-name)
|
||||
(ctob/get-token token-name)))))
|
||||
|
||||
(defn- set-stroke-width
|
||||
[shape stroke-width]
|
||||
(let [strokes (if (seq (:strokes shape))
|
||||
|
|
198
common/test/common_tests/logic/token_apply_test.cljc
Normal file
198
common/test/common_tests/logic/token_apply_test.cljc
Normal file
|
@ -0,0 +1,198 @@
|
|||
;; 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 common-tests.logic.token-apply-test
|
||||
(:require
|
||||
[app.common.files.changes-builder :as pcb]
|
||||
[app.common.logic.shapes :as cls]
|
||||
[app.common.test-helpers.compositions :as tho]
|
||||
[app.common.test-helpers.files :as thf]
|
||||
[app.common.test-helpers.ids-map :as thi]
|
||||
[app.common.test-helpers.shapes :as ths]
|
||||
[app.common.test-helpers.tokens :as tht]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.common.types.token :as cto]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[clojure.test :as t]))
|
||||
|
||||
(t/use-fixtures :each thi/test-fixture)
|
||||
|
||||
(defn- setup-file
|
||||
[]
|
||||
(-> (thf/sample-file :file1)
|
||||
(tht/add-tokens-lib)
|
||||
(tht/update-tokens-lib #(-> %
|
||||
(ctob/add-set (ctob/make-token-set :name "test-token-set"))
|
||||
(ctob/add-theme (ctob/make-token-theme :name "test-theme"
|
||||
:sets #{"test-token-set"}))
|
||||
(ctob/set-active-themes #{"/test-theme"})
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "token-radius"
|
||||
:type :border-radius
|
||||
:value 10))
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "token-rotation"
|
||||
:type :rotation
|
||||
:value 30))
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "token-opacity"
|
||||
:type :opacity
|
||||
:value 0.7))
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "token-stroke-width"
|
||||
:type :stroke-width
|
||||
:value 2))
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "token-color"
|
||||
:type :color
|
||||
:value "#00ff00"))
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "token-dimensions"
|
||||
:type :dimensions
|
||||
:value 100))))
|
||||
(tho/add-frame :frame1)))
|
||||
|
||||
(defn- apply-all-tokens
|
||||
[file]
|
||||
(-> file
|
||||
(tht/apply-token-to-shape :frame1 "token-radius" [:rx :ry] [:rx :ry] 10)
|
||||
(tht/apply-token-to-shape :frame1 "token-rotation" [:rotation] [:rotation] 30)
|
||||
(tht/apply-token-to-shape :frame1 "token-opacity" [:opacity] [:opacity] 0.7)
|
||||
(tht/apply-token-to-shape :frame1 "token-stroke-width" [:stroke-width] [:stroke-width] 2)
|
||||
(tht/apply-token-to-shape :frame1 "token-color" [:stroke-color] [:stroke-color] "#00ff00")
|
||||
(tht/apply-token-to-shape :frame1 "token-color" [:fill] [:fill] "#00ff00")
|
||||
(tht/apply-token-to-shape :frame1 "token-dimensions" [:width :height] [:width :height] 100)))
|
||||
|
||||
(t/deftest apply-tokens-to-shape
|
||||
(let [;; ==== Setup
|
||||
file (setup-file)
|
||||
page (thf/current-page file)
|
||||
frame1 (ths/get-shape file :frame1)
|
||||
token-radius (tht/get-token file "test-token-set" "token-radius")
|
||||
token-rotation (tht/get-token file "test-token-set" "token-rotation")
|
||||
token-opacity (tht/get-token file "test-token-set" "token-opacity")
|
||||
token-stroke-width (tht/get-token file "test-token-set" "token-stroke-width")
|
||||
token-color (tht/get-token file "test-token-set" "token-color")
|
||||
token-dimensions (tht/get-token file "test-token-set" "token-dimensions")
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page page)
|
||||
(pcb/with-objects (:objects page)))
|
||||
(cls/generate-update-shapes [(:id frame1)]
|
||||
(fn [shape]
|
||||
(as-> shape $
|
||||
(cto/maybe-apply-token-to-shape {:token nil ; test nil case
|
||||
:shape $
|
||||
:attributes []})
|
||||
(cto/maybe-apply-token-to-shape {:token token-radius
|
||||
:shape $
|
||||
:attributes [:rx :ry]})
|
||||
(cto/maybe-apply-token-to-shape {:token token-rotation
|
||||
:shape $
|
||||
:attributes [:rotation]})
|
||||
(cto/maybe-apply-token-to-shape {:token token-opacity
|
||||
:shape $
|
||||
:attributes [:opacity]})
|
||||
(cto/maybe-apply-token-to-shape {:token token-stroke-width
|
||||
:shape $
|
||||
:attributes [:stroke-width]})
|
||||
(cto/maybe-apply-token-to-shape {:token token-color
|
||||
:shape $
|
||||
:attributes [:stroke-color]})
|
||||
(cto/maybe-apply-token-to-shape {:token token-color
|
||||
:shape $
|
||||
:attributes [:fill]})
|
||||
(cto/maybe-apply-token-to-shape {:token token-dimensions
|
||||
:shape $
|
||||
:attributes [:width :height]})))
|
||||
(:objects page)
|
||||
{}))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
frame1' (ths/get-shape file' :frame1)
|
||||
applied-tokens' (:applied-tokens frame1')]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (count applied-tokens') 9))
|
||||
(t/is (= (:rx applied-tokens') "token-radius"))
|
||||
(t/is (= (:ry applied-tokens') "token-radius"))
|
||||
(t/is (= (:rotation applied-tokens') "token-rotation"))
|
||||
(t/is (= (:opacity applied-tokens') "token-opacity"))
|
||||
(t/is (= (:stroke-width applied-tokens') "token-stroke-width"))
|
||||
(t/is (= (:stroke-color applied-tokens') "token-color"))
|
||||
(t/is (= (:fill applied-tokens') "token-color"))
|
||||
(t/is (= (:width applied-tokens') "token-dimensions"))
|
||||
(t/is (= (:height applied-tokens') "token-dimensions"))))
|
||||
|
||||
(t/deftest unapply-tokens-from-shape
|
||||
(let [;; ==== Setup
|
||||
file (-> (setup-file)
|
||||
(apply-all-tokens))
|
||||
page (thf/current-page file)
|
||||
frame1 (ths/get-shape file :frame1)
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page page)
|
||||
(pcb/with-objects (:objects page)))
|
||||
(cls/generate-update-shapes [(:id frame1)]
|
||||
(fn [shape]
|
||||
(-> shape
|
||||
(cto/unapply-token-id [:rx :ry])
|
||||
(cto/unapply-token-id [:rotation])
|
||||
(cto/unapply-token-id [:opacity])
|
||||
(cto/unapply-token-id [:stroke-width])
|
||||
(cto/unapply-token-id [:stroke-color])
|
||||
(cto/unapply-token-id [:fill])
|
||||
(cto/unapply-token-id [:width :height])))
|
||||
(:objects page)
|
||||
{}))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
frame1' (ths/get-shape file' :frame1)
|
||||
applied-tokens' (:applied-tokens frame1')]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (count applied-tokens') 0))))
|
||||
|
||||
(t/deftest unapply-tokens-automatic
|
||||
(let [;; ==== Setup
|
||||
file (-> (setup-file)
|
||||
(apply-all-tokens))
|
||||
page (thf/current-page file)
|
||||
frame1 (ths/get-shape file :frame1)
|
||||
|
||||
;; ==== Action
|
||||
changes (-> (-> (pcb/empty-changes nil)
|
||||
(pcb/with-page page)
|
||||
(pcb/with-objects (:objects page)))
|
||||
(cls/generate-update-shapes [(:id frame1)]
|
||||
(fn [shape]
|
||||
(-> shape
|
||||
(ctn/set-shape-attr :rx 0)
|
||||
(ctn/set-shape-attr :ry 0)
|
||||
(ctn/set-shape-attr :rotation 0)
|
||||
(ctn/set-shape-attr :opacity 0)
|
||||
(ctn/set-shape-attr :strokes [])
|
||||
(ctn/set-shape-attr :fills [])
|
||||
(ctn/set-shape-attr :width 0)
|
||||
(ctn/set-shape-attr :height 0)))
|
||||
(:objects page)
|
||||
{}))
|
||||
|
||||
file' (thf/apply-changes file changes)
|
||||
|
||||
;; ==== Get
|
||||
frame1' (ths/get-shape file' :frame1)
|
||||
applied-tokens' (:applied-tokens frame1')]
|
||||
|
||||
;; ==== Check
|
||||
(t/is (= (count applied-tokens') 0))))
|
|
@ -297,27 +297,27 @@
|
|||
(ctob/add-theme (ctob/make-token-theme :name "test-theme"
|
||||
:sets #{"test-token-set"}))
|
||||
(ctob/set-active-themes #{"/test-theme"})
|
||||
(ctob/add-token-in-set "token-radius"
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "token-radius"
|
||||
:type :border-radius
|
||||
:value 10))
|
||||
(ctob/add-token-in-set "token-rotation"
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "token-rotation"
|
||||
:type :rotation
|
||||
:value 30))
|
||||
(ctob/add-token-in-set "token-opacity"
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "token-opacity"
|
||||
:type :opacity
|
||||
:value 0.7))
|
||||
(ctob/add-token-in-set "token-stroke-width"
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "token-stroke-width"
|
||||
:type :stroke-width
|
||||
:value 2))
|
||||
(ctob/add-token-in-set "token-color"
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "token-color"
|
||||
:type :color
|
||||
:value "#00ff00"))
|
||||
(ctob/add-token-in-set "token-dimensions"
|
||||
(ctob/add-token-in-set "test-token-set"
|
||||
(ctob/make-token :name "token-dimensions"
|
||||
:type :dimensions
|
||||
:value 100))))
|
||||
|
|
|
@ -4,11 +4,6 @@
|
|||
[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)
|
||||
|
|
Loading…
Add table
Reference in a new issue