0
Fork 0
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:
Andrés Moya 2024-12-11 14:25:24 +01:00 committed by Andrés Moya
parent 05ec84ca1b
commit edfa80d5b1
5 changed files with 243 additions and 13 deletions

View file

@ -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

View file

@ -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))

View 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))))

View file

@ -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))))

View file

@ -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)