Compare commits

...

9 Commits

Author SHA1 Message Date
Andrey Antukh
d4b7f231c7 🔧 Add missing config for on commit checker 2025-09-29 12:05:09 +02:00
Eva Marco
e184a9a8b9 🐛 Fix context menu on spacing tokens (#7382) 2025-09-25 17:28:46 +02:00
Eva Marco
a4ada6dc8a 🐛 Add default flags for tokens (#7367) 2025-09-25 08:47:04 +02:00
Andrey Antukh
11b75408fe 🐛 Fix regression on importing binfile-v1 files (#7359) 2025-09-23 11:38:33 +02:00
Andrey Antukh
59f7ede4ff 🐛 Add migration for properly decode all position data on text shapes 2025-09-23 11:34:24 +02:00
Andrés Moya
8954b05d76 🐛 Fix error exporting a file with deleted tokens (#7356) 2025-09-22 17:41:31 +02:00
Andrey Antukh
cb4c155b32 📎 Uncomment previously commented migrations 2025-09-22 11:38:52 +02:00
Andrey Antukh
0b346e02ff 🐛 Fix incorrect options pass on decode-file 2025-09-22 11:30:42 +02:00
Andrey Antukh
946f641917 📎 Disable possible problematic migrations 2025-09-22 11:12:43 +02:00
14 changed files with 87 additions and 41 deletions

View File

@@ -26,7 +26,7 @@ jobs:
- name: Check Commit Type
uses: gsactions/commit-message-checker@v2
with:
pattern: '^(Merge|Revert|:(lipstick|globe_with_meridians|wrench|books|arrow_up|arrow_down|zap|ambulance|construction|boom|fire|whale|bug|sparkles|paperclip|tada|recycle):)\s[A-Z].*[^.]$'
pattern: '^(Merge|Revert|:(lipstick|globe_with_meridians|wrench|books|arrow_up|arrow_down|zap|ambulance|construction|boom|fire|whale|bug|sparkles|paperclip|tada|recycle|rewind):)\s[A-Z].*[^.]$'
flags: 'gm'
error: 'Commit should match CONTRIBUTING.md guideline'
checkAllCommitMessages: 'true' # optional: this checks all commits associated with a pull request

View File

@@ -62,6 +62,8 @@
- Fix moving elements up or down while pressing alt [Taiga Issue #11992](https://tree.taiga.io/project/penpot/issue/11992)
- Fix conflicting shortcuts (remove dec/inc line height and letter spacing) [Taiga #12102](https://tree.taiga.io/project/penpot/issue/12102)
- Fix conflicting shortcuts (remove text-align shortcuts) [Taiga #12047](https://tree.taiga.io/project/penpot/issue/12047)
- Fix export file with empty tokens library [Taiga #12137](https://tree.taiga.io/project/penpot/issue/12137)
- Fix context menu on spacing tokens [Taiga #12141](https://tree.taiga.io/project/penpot/issue/12141)
## 2.9.0

View File

@@ -6,22 +6,24 @@
(ns user
(:require
[app.binfile.common :as bfc]
[app.common.data :as d]
[app.common.debug :as debug]
[app.common.exceptions :as ex]
[app.common.files.helpers :as cfh]
[app.common.fressian :as fres]
[app.common.geom.matrix :as gmt]
[app.common.json :as json]
[app.common.logging :as l]
[app.common.perf :as perf]
[app.common.pprint :as pp]
[app.common.schema :as sm]
[app.common.schema.desc-js-like :as smdj]
[app.common.schema.desc-native :as smdn]
[app.common.schema.openapi :as oapi]
[app.common.schema.generators :as sg]
[app.common.schema.openapi :as oapi]
[app.common.spec :as us]
[app.common.json :as json]
[app.common.time :as ct]
[app.common.transit :as t]
[app.common.types.file :as ctf]
[app.common.uuid :as uuid]
@@ -31,7 +33,6 @@
[app.srepl.helpers :as srepl.helpers]
[app.srepl.main :as srepl]
[app.util.blob :as blob]
[app.common.time :as ct]
[clj-async-profiler.core :as prof]
[clojure.contrib.humanize :as hum]
[clojure.java.io :as io]

View File

@@ -188,9 +188,9 @@
and decoding."
[cfg file-id & {:as opts}]
(db/run! cfg (fn [{:keys [::db/conn] :as cfg}]
(some->> (db/get* conn :file {:id file-id}
(assoc opts ::db/remove-deleted false))
(decode-file cfg)))))
(when-let [row (db/get* conn :file {:id file-id}
(assoc opts ::db/remove-deleted false))]
(decode-file cfg row opts)))))
(defn clean-file-features
[file]

View File

@@ -27,7 +27,7 @@
[app.common.types.page :as ctp]
[app.common.types.plugins :as ctpg]
[app.common.types.shape :as cts]
[app.common.types.tokens-lib :as cto]
[app.common.types.tokens-lib :as ctob]
[app.common.types.typography :as cty]
[app.common.uuid :as uuid]
[app.config :as cf]
@@ -120,7 +120,7 @@
(sm/encoder cty/schema:typography sm/json-transformer))
(def encode-tokens-lib
(sm/encoder cto/schema:tokens-lib sm/json-transformer))
(sm/encoder ctob/schema:tokens-lib sm/json-transformer))
(def encode-plugin-data
(sm/encoder ctpg/schema:plugin-data sm/json-transformer))
@@ -158,7 +158,7 @@
(sm/decoder cty/schema:typography sm/json-transformer))
(def decode-tokens-lib
(sm/decoder cto/schema:tokens-lib sm/json-transformer))
(sm/decoder ctob/schema:tokens-lib sm/json-transformer))
(def decode-plugin-data
(sm/decoder ctpg/schema:plugin-data sm/json-transformer))
@@ -196,7 +196,7 @@
(sm/check-fn cty/schema:typography))
(def validate-tokens-lib
(sm/check-fn cto/schema:tokens-lib))
(sm/check-fn ctob/schema:tokens-lib))
(def validate-plugin-data
(sm/check-fn ctpg/schema:plugin-data))
@@ -349,7 +349,8 @@
typography (encode-typography object)]
(write-entry! output path typography)))
(when tokens-lib
(when (and tokens-lib
(not (ctob/empty-lib? tokens-lib)))
(let [path (str "files/" file-id "/tokens.json")
encoded-tokens (encode-tokens-lib tokens-lib)]
(write-entry! output path encoded-tokens)))))

View File

@@ -31,6 +31,7 @@
[app.common.types.shape :as cts]
[app.common.types.shape.interactions :as ctsi]
[app.common.types.shape.shadow :as ctss]
[app.common.types.shape.text :as ctst]
[app.common.types.text :as types.text]
[app.common.uuid :as uuid]
[clojure.set :as set]
@@ -1585,6 +1586,25 @@
(-> data
(update :pages-index d/update-vals update-page))))
(defmethod migrate-data "0012-fix-position-data"
[data _]
(let [decode-fn
(sm/decoder ctst/schema:position-data sm/json-transformer)
update-object
(fn [object]
(if (cfh/text-shape? object)
(d/update-when object :position-data decode-fn)
object))
update-container
(fn [container]
(d/update-when container :objects d/update-vals update-object))]
(-> data
(update :pages-index d/update-vals update-container)
(d/update-when :components d/update-vals update-container))))
(def available-migrations
(into (d/ordered-set)
["legacy-2"
@@ -1652,4 +1672,5 @@
"0009-clean-library-colors"
"0009-add-partial-text-touched-flags"
"0010-fix-swap-slots-pointing-non-existent-shapes"
"0011-fix-invalid-text-touched-flags"]))
"0011-fix-invalid-text-touched-flags"
"0012-fix-position-data"]))

View File

@@ -156,7 +156,9 @@
:enable-dashboard-templates-section
:enable-google-fonts-provider
:enable-component-thumbnails
:enable-render-wasm-dpr])
:enable-render-wasm-dpr
:enable-token-units
:enable-token-typography-types])
(defn parse
[& flags]

View File

@@ -139,6 +139,13 @@
(def spacing-keys (schema-keys schema:spacing))
(def ^:private schema:spacing-gap-padding
(-> (reduce mu/union [schema:spacing-gap
schema:spacing-padding])
(mu/update-properties assoc :title "SpacingGapPaddingTokenAttrs")))
(def spacing-gap-padding-keys (schema-keys schema:spacing-gap-padding))
(def ^:private schema:dimensions
(-> (reduce mu/union [schema:sizing
schema:spacing
@@ -320,9 +327,9 @@
(set/union generic-attributes
border-radius-keys))
(def frame-attributes
(def frame-with-layout-attributes
(set/union rect-attributes
spacing-keys))
spacing-gap-padding-keys))
(def text-attributes
(set/union generic-attributes
@@ -330,12 +337,14 @@
number-keys))
(defn shape-type->attributes
[type]
[type is-layout]
(case type
:bool generic-attributes
:circle generic-attributes
:rect rect-attributes
:frame frame-attributes
:frame (if is-layout
frame-with-layout-attributes
rect-attributes)
:image rect-attributes
:path generic-attributes
:svg-raw generic-attributes
@@ -343,14 +352,14 @@
nil))
(defn appliable-attrs
"Returns intersection of shape `attributes` for `token-type`."
[attributes token-type]
(set/intersection attributes (shape-type->attributes token-type)))
"Returns intersection of shape `attributes` for `shape-type`."
[attributes shape-type is-layout]
(set/intersection attributes (shape-type->attributes shape-type is-layout)))
(defn any-appliable-attr?
"Checks if `token-type` supports given shape `attributes`."
[attributes token-type]
(seq (appliable-attrs attributes token-type)))
[attributes token-type is-layout]
(seq (appliable-attrs attributes token-type is-layout)))
;; Token attrs that are set inside content blocks of text shapes, instead
;; at the shape level.

View File

@@ -768,7 +768,8 @@
(theme-active? [_ group name] "predicate if token theme is active")
(activate-theme [_ group name] "adds theme from the active-themes")
(deactivate-theme [_ group name] "removes theme from the active-themes")
(toggle-theme-active? [_ group name] "toggles theme in the active-themes"))
(toggle-theme-active? [_ group name] "toggles theme in the active-themes")
(get-hidden-theme [_] "get the hidden temporary theme"))
(def schema:token-themes
[:and
@@ -906,6 +907,7 @@
(defprotocol ITokensLib
"A library of tokens, sets and themes."
(empty-lib? [_] "True if the lib does not contain any token, set or theme")
(set-path-exists? [_ path] "if a set at `path` exists")
(set-group-path-exists? [_ path] "if a set group at `path` exists")
(add-token-in-set [_ set-name token] "add token to a set")
@@ -1235,7 +1237,16 @@ Will return a value that matches this schema:
(filter #(theme-active? this (:group %) (:name %))))
(tree-seq d/ordered-map? vals themes)))
(get-hidden-theme [this]
(get-theme this hidden-theme-group hidden-theme-name))
ITokensLib
(empty-lib? [this]
(and (empty? sets)
(or (empty? themes)
(and (= (theme-count this) 1)
(get-hidden-theme this)))))
(set-path-exists? [_ set-path]
(some? (get-in sets (set-full-path->set-prefixed-full-path set-path))))
@@ -1338,10 +1349,6 @@ Will return a value that matches this schema:
cljs.core/IEncodeJS
(-clj->js [this] (clj->js (datafy this)))))
(defn get-hidden-theme
[tokens-lib]
(get-theme tokens-lib hidden-theme-group hidden-theme-name))
(defn valid-tokens-lib?
[o]
(and (instance? TokensLib o)
@@ -1752,11 +1759,12 @@ Will return a value that matches this schema:
active-set-names
(get-active-themes-set-names tokens-lib)]
(-> sets
(assoc "$themes" themes)
(assoc "$metadata" {"tokenSetOrder" ordered-set-names
"activeThemes" active-themes
"activeSets" active-set-names}))))
(when-not (empty-lib? tokens-lib)
(-> sets
(assoc "$themes" themes)
(assoc "$metadata" {"tokenSetOrder" ordered-set-names
"activeThemes" active-themes
"activeSets" active-set-names})))))
(defn get-tokens-of-unknown-type
"Search for all tokens in the decoded json file that have a type that is not currently

View File

@@ -487,7 +487,7 @@
(or
(and (ctsl/any-layout-immediate-child? objects shape)
(some ctt/spacing-margin-keys attributes))
(ctt/any-appliable-attr? attributes (:type shape))))))
(ctt/any-appliable-attr? attributes (:type shape) (:layout shape))))))
shape-ids (d/nilv (keys shapes) [])
any-variant? (->> shapes vals (some ctk/is-variant?) boolean)

View File

@@ -341,7 +341,7 @@
(:id token)))}]))
(defn- allowed-shape-attributes [shapes]
(reduce into #{} (map #(ctt/shape-type->attributes (:type %)) shapes)))
(reduce into #{} (map #(ctt/shape-type->attributes (:type %) (:layout %)) shapes)))
(defn menu-actions [{:keys [type token selected-shapes] :as context-data}]
(let [context-data (assoc context-data :allowed-shape-attributes (allowed-shape-attributes selected-shapes))
@@ -445,7 +445,8 @@
(if (some? type)
(submenu-actions-selection-actions context-data)
(selection-actions context-data))
(default-actions context-data))]
(default-actions context-data))
entries (clean-separators entries)]
(for [[index {:keys [title action selected? hint submenu no-selectable] :as entry}] (d/enumerate entries)]
[:* {:key (dm/str title " " index)}
(cond

View File

@@ -191,7 +191,7 @@
;; Edge-case for allowing margin attribute on shapes inside layout parent
(and selected-inside-layout? (set/subset? ctt/spacing-margin-keys attrs))
(some (fn [shape]
(ctt/any-appliable-attr? attrs (:type shape)))
(ctt/any-appliable-attr? attrs (:type shape) (:layout shape)))
selected-shapes)))
(def token-types-with-status-icon

View File

@@ -148,6 +148,7 @@
(->> (rp/cmd! ::sse/import-binfile
{:name (str/replace (:name data) #".penpot$" "")
:file file
:version 1
:project-id project-id})
(rx/tap (fn [event]
(let [payload (sse/get-payload event)

View File

@@ -296,10 +296,10 @@
frame-1' (cths/get-shape file' :frame-1)
frame-2' (cths/get-shape file' :frame-2)]
(t/testing "shape `:applied-tokens` got updated"
(t/is (= (:p1 (:applied-tokens frame-1')) (:name token-target')))
(t/is (= (:p2 (:applied-tokens frame-1')) (:name token-target')))
(t/is (= (:p3 (:applied-tokens frame-1')) (:name token-target')))
(t/is (= (:p4 (:applied-tokens frame-1')) (:name token-target')))
(t/is (= (:p1 (:applied-tokens frame-1')) nil))
(t/is (= (:p2 (:applied-tokens frame-1')) nil))
(t/is (= (:p3 (:applied-tokens frame-1')) nil))
(t/is (= (:p4 (:applied-tokens frame-1')) nil))
(t/is (= (:p1 (:applied-tokens frame-2')) (:name token-target')))
(t/is (= (:p2 (:applied-tokens frame-2')) (:name token-target')))