mirror of
https://github.com/penpot/penpot.git
synced 2026-09-22 20:06:16 +00:00
* ✨ Auto link tokens when adding external libraries (provisional) * 🔧 Refactor tokens-lib initialization * 🔧 Add separated TokenStatus to store status apart of TokensLib * 🔧 Make all status operations use the new data structure * 🔧 Normalize status helper functions and access token sets by id * 🔧 Rename :tokens-file to :tokens-source * 🎉 Allow the user to choose the tokens-source of a file * 🎉 Make tokens library readonly when it's in an external file * 🎉 Show tokens in library summaries * 🎉 Show source info in sidebar * 🔧 Fix integration tests * 🐛 Propagate changes of token values in external library * 🎉 Layout updates * 🔧 Refactor tokens source calculations * 🔧 Add harder checks for nil or empty values in everything * 🐛 Fix some integration tests * 🔧 Add integration tests for tokens in external libs * 🔧 Validate and repair missing tokens status * 🎉 Make ui changes optional with config flag * 🐛 Propagate tokens after synchronizing components in ext library * 🐛 Propagate tokens after creating new instances * 🐛 Propagate tokens after synchronizing tokens in ext library * 🐛 Add a tokens source icon to libraries section (#11439) * 🐛 Add a tokens source icon to libraries section * 🐛 Fix ellipsis on library names * ♻️ Remove code under flag on legacy component * 🐛 Fix token theme name on inspect tab * 🎉 Add changes notification (#11476) * 🎉 Add changes notification * ♻️ Change fn names * 🐛 Fix tokens source label truncation and missing translations (#11533) * 🐛 Fix tokens source label truncation and missing translations The tokens source file name always showed, even for the current file, and long names wrapped onto a second line instead of truncating because the header used flex-wrap and overflow-wrap: break-word instead of single-line ellipsis. Show the source row unconditionally (it now displays "This file" when the source is the current file, matching the connected-library case), truncate the file name to one line with an ellipsis, and only attach a tooltip with the full name when the text is actually truncated. Replace the hardcoded UI strings with translated ones and add their English and Spanish entries. AI-assisted-by: claude-sonnet-5 * 🐛 Remove redundant effect dependency in tokens source file-name-truncated? was listed as a dependency of the with-effect that checks and observes label truncation, even though it isn't read inside the effect body. Since the effect itself flips that state via check-file-name-truncated, including it as a dependency caused the ResizeObserver to be needlessly disconnected and reconnected on every truncation change. AI-assisted-by: claude-sonnet-5 * 🐛 Fix small visual error * 🐛 Fix problem with plugins * 🐛 Fix playwright tests --------- Co-authored-by: Eva Marco <evamarcod@gmail.com> Co-authored-by: Eva Marco <eva.marco@kaleidos.net> Co-authored-by: alonso.torres <alonso.torres@kaleidos.net>
219 lines
11 KiB
Clojure
219 lines
11 KiB
Clojure
;; 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 SUBSIDIARY SL
|
|
|
|
(ns common-tests.logic.move-shapes-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.tokens-lib :as ctob]
|
|
[app.common.types.tokens-status :as ctos]
|
|
[app.common.uuid :as uuid]
|
|
[clojure.test :as t]))
|
|
|
|
(t/use-fixtures :each thi/test-fixture)
|
|
|
|
(t/deftest test-relocate-shape
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(tho/add-frame :frame-to-move)
|
|
(tho/add-frame :frame-parent))
|
|
|
|
page (thf/current-page file)
|
|
frame-to-move (ths/get-shape file :frame-to-move)
|
|
frame-parent (ths/get-shape file :frame-parent)
|
|
|
|
;; ==== Action
|
|
|
|
changes (cls/generate-relocate (-> (pcb/empty-changes nil)
|
|
(pcb/with-page-id (:id page))
|
|
(pcb/with-objects (:objects page)))
|
|
(:id frame-parent) ;; parent-id
|
|
0 ;; to-index
|
|
#{(:id frame-to-move)}) ;; ids
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
frame-to-move' (ths/get-shape file' :frame-to-move)
|
|
frame-parent' (ths/get-shape file' :frame-parent)]
|
|
|
|
;; ==== Check
|
|
;; frame-to-move has moved
|
|
(t/is (= (:parent-id frame-to-move) uuid/zero))
|
|
(t/is (= (:parent-id frame-to-move') (:id frame-parent')))))
|
|
|
|
(t/deftest test-relocate-shape-out-of-group
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(tho/add-frame :frame-1)
|
|
(tho/add-group :group-1 :parent-label :frame-1)
|
|
(ths/add-sample-shape :circle-1 :parent-label :group-1))
|
|
|
|
page (thf/current-page file)
|
|
circle (ths/get-shape file :circle-1)
|
|
group (ths/get-shape file :group-1)
|
|
|
|
;; ==== Action
|
|
|
|
changes (cls/generate-relocate (-> (pcb/empty-changes nil)
|
|
(pcb/with-page-id (:id page))
|
|
(pcb/with-objects (:objects page)))
|
|
uuid/zero ;; parent-id
|
|
0 ;; to-index
|
|
#{(:id circle)}) ;; ids
|
|
|
|
file' (thf/apply-changes file changes)
|
|
|
|
;; ==== Get
|
|
circle' (ths/get-shape file' :circle-1)
|
|
group' (ths/get-shape file' :group-1)]
|
|
|
|
;; ==== Check
|
|
|
|
;; the circle has moved, and the group is deleted
|
|
(t/is (= (:parent-id circle) (:id group)))
|
|
(t/is (= (:parent-id circle') uuid/zero))
|
|
(t/is group)
|
|
(t/is (nil? group'))))
|
|
|
|
(t/deftest test-relocate-shape-out-of-layout-manual
|
|
(let [;; ==== Setup
|
|
file (-> (thf/sample-file :file1)
|
|
(tho/add-frame :frame-1
|
|
:layout :flex ;; TODO: those values come from main.data.workspace.shape_layout/default-layout-params
|
|
:layout-flex-dir :row ;; it should be good to use it directly, but first it should be moved to common.logic
|
|
:layout-gap-type :multiple
|
|
:layout-gap {:row-gap 0 :column-gap 0}
|
|
:layout-align-items :start
|
|
:layout-justify-content :start
|
|
:layout-align-content :stretch
|
|
:layout-wrap-type :nowrap
|
|
:layout-padding-type :simple
|
|
:layout-padding {:p1 0 :p2 0 :p3 0 :p4 0})
|
|
(ths/add-sample-shape :circle-1 :parent-label :frame-1
|
|
:layout-item-margin {:m1 10 :m2 10 :m3 10 :m4 10}
|
|
:layout-item-margin-type :multiple
|
|
:layout-item-h-sizing :auto
|
|
:layout-item-v-sizing :auto
|
|
:layout-item-max-h 1000
|
|
:layout-item-min-h 100
|
|
:layout-item-max-w 2000
|
|
:layout-item-min-w 200
|
|
:layout-item-absolute false
|
|
:layout-item-z-index 10))
|
|
|
|
page (thf/current-page file)
|
|
circle (ths/get-shape file :circle-1)
|
|
|
|
;; ==== Action
|
|
|
|
changes (cls/generate-relocate (-> (pcb/empty-changes nil)
|
|
(pcb/with-page-id (:id page))
|
|
(pcb/with-objects (:objects page)))
|
|
uuid/zero ;; parent-id
|
|
0 ;; to-index
|
|
#{(:id circle)}) ;; ids
|
|
|
|
;; ==== Get
|
|
file' (thf/apply-changes file changes)
|
|
circle' (ths/get-shape file' :circle-1)]
|
|
|
|
;; ==== Check
|
|
|
|
;; the layout item attributes are removed
|
|
(t/is (nil? (:layout-item-margin circle')))
|
|
(t/is (nil? (:layout-item-margin-type circle')))
|
|
(t/is (nil? (:layout-item-h-sizing circle')))
|
|
(t/is (nil? (:layout-item-v-sizing circle')))
|
|
(t/is (nil? (:layout-item-max-h circle')))
|
|
(t/is (nil? (:layout-item-min-h circle')))
|
|
(t/is (nil? (:layout-item-max-w circle')))
|
|
(t/is (nil? (:layout-item-min-w circle')))
|
|
(t/is (nil? (:layout-item-absolute circle')))
|
|
(t/is (nil? (:layout-item-z-index circle')))))
|
|
|
|
(t/deftest test-relocate-shape-out-of-layout-with-tokens
|
|
(let [;; ==== Setup
|
|
file (-> (tht/sample-file-with-tokens
|
|
:lib-fn #(-> %
|
|
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :test-token-set)
|
|
:name "test-token-set"))
|
|
(ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :test-theme)
|
|
:name "test-theme"
|
|
:sets #{"test-token-set"}))
|
|
(ctob/add-token (thi/id :test-token-set)
|
|
(ctob/make-token :id (thi/new-id! :token-sizing)
|
|
:name "token-sizing"
|
|
:type :sizing
|
|
:value 10))
|
|
(ctob/add-token (thi/id :test-token-set)
|
|
(ctob/make-token :id (thi/new-id! :token-spacing)
|
|
:name "token-spacing"
|
|
:type :spacing
|
|
:value 30)))
|
|
:status-fn #(-> %
|
|
(ctos/set-tokens-status #{(thi/id :test-theme)}
|
|
#{(thi/id :test-token-set)})))
|
|
;; Sync tokens-status from lib's internal active-themes
|
|
(tho/add-frame :frame-1
|
|
:layout :flex ;; TODO: those values come from main.data.workspace.shape_layout/default-layout-params
|
|
:layout-flex-dir :row ;; it should be good to use it directly, but first it should be moved to common.logic
|
|
:layout-gap-type :multiple
|
|
:layout-gap {:row-gap 0 :column-gap 0}
|
|
:layout-align-items :start
|
|
:layout-justify-content :start
|
|
:layout-align-content :stretch
|
|
:layout-wrap-type :nowrap
|
|
:layout-padding-type :simple
|
|
:layout-padding {:p1 0 :p2 0 :p3 0 :p4 0})
|
|
(ths/add-sample-shape :circle-1 :parent-label :frame-1)
|
|
(tht/apply-token-to-shape :circle-1
|
|
"token-sizing"
|
|
[:layout-item-max-h :layout-item-max-w :layout-item-min-h :layout-item-min-w]
|
|
[:layout-item-max-h :layout-item-max-w :layout-item-min-h :layout-item-min-w]
|
|
10)
|
|
(tht/apply-token-to-shape :circle-1
|
|
"token-spacing"
|
|
[:m1 :m2 :m3 :m4]
|
|
[:layout-item-margin]
|
|
{:m1 30 :m2 30 :m3 30 :m4 30}))
|
|
|
|
page (thf/current-page file)
|
|
circle (ths/get-shape file :circle-1)
|
|
|
|
;; ==== Action
|
|
|
|
changes (cls/generate-relocate (-> (pcb/empty-changes nil)
|
|
(pcb/with-page-id (:id page))
|
|
(pcb/with-objects (:objects page)))
|
|
uuid/zero ;; parent-id
|
|
0 ;; to-index
|
|
#{(:id circle)}) ;; ids
|
|
|
|
|
|
;; ==== Get
|
|
file' (thf/apply-changes file changes)
|
|
circle' (ths/get-shape file' :circle-1)]
|
|
|
|
;; ==== Check
|
|
|
|
;; the layout item attributes and tokens are removed
|
|
(t/is (empty? (:applied-tokens circle')))
|
|
(t/is (nil? (:layout-item-margin circle')))
|
|
(t/is (nil? (:layout-item-margin-type circle')))
|
|
(t/is (nil? (:layout-item-h-sizing circle')))
|
|
(t/is (nil? (:layout-item-v-sizing circle')))
|
|
(t/is (nil? (:layout-item-max-h circle')))
|
|
(t/is (nil? (:layout-item-min-h circle')))
|
|
(t/is (nil? (:layout-item-max-w circle')))
|
|
(t/is (nil? (:layout-item-min-w circle')))
|
|
(t/is (nil? (:layout-item-absolute circle')))
|
|
(t/is (nil? (:layout-item-z-index circle'))))) |