Compare commits

..

15 Commits

Author SHA1 Message Date
Andres Gonzalez
08ee5e34cd 📚 Change link to post at SH guide 2026-01-30 09:26:58 +01:00
David Barragán Merino
76bd31fe7d 🔧 Fix CORS error 2026-01-28 13:40:45 +01:00
David Barragán Merino
77bbf30ae4 🔧 Fix file name 2026-01-27 21:16:44 +01:00
David Barragán Merino
693b52bf45 📚 Fix links related to penpot plugins 2026-01-27 21:16:44 +01:00
David Barragán Merino
0f51b23ce7 🔧 Deploy plugin styles documentation 2026-01-27 21:16:44 +01:00
David Barragán Merino
ec61aa6b6d 🔧 Add custom domain 2026-01-27 21:16:41 +01:00
Andrey Antukh
abc1773f65 Merge tag '2.13.0-RC9' 2026-01-26 18:12:16 +01:00
David Barragán Merino
93f5e74bb0 🔧 Run all the jobs if the workflow is launched manually 2026-01-26 17:14:15 +01:00
David Barragán Merino
38179ba11e 🔧 Enable secret inheritance 2026-01-26 14:01:22 +01:00
David Barragán Merino
719a95246a 🔧 Define deploy plugin packages workflows 2026-01-26 13:48:33 +01:00
David Barragán Merino
e590cd852d 🔧 Rename wrangle to wrangler 2026-01-26 13:48:33 +01:00
David Barragán Merino
a9741073e5 🔧 Add deploy plugin packages workflow placeholder and wrangle config files 2026-01-26 13:48:33 +01:00
David Barragán Merino
599656c31e 🔧 Fix a typo in an interpolation 2026-01-23 19:52:47 +01:00
David Barragán Merino
16f22a7b5c 🔧 Fixes to the API documentation deployer 2026-01-22 12:10:27 +01:00
David Barragán Merino
a1460115e8 🔧 Deploy penpot api documentation 2026-01-22 12:10:27 +01:00
19 changed files with 69 additions and 112 deletions

View File

@@ -45,15 +45,6 @@
:potok/reify-type
{:level :error}
:redundant-primitive-coercion
{:level :off}
:unused-excluded-var
{:level :off}
:unresolved-excluded-var
{:level :off}
:missing-protocol-method
{:level :off}

View File

@@ -110,16 +110,4 @@ jobs:
workingDirectory: plugins
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: deploy --config wrangler-penpot-plugins-api-doc.toml --name ${{ env.WORKER_NAME }}
- name: Notify Mattermost
if: failure()
uses: mattermost/action-mattermost-notify@master
with:
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK }}
MATTERMOST_CHANNEL: bot-alerts-cicd
TEXT: |
❌ 🧩📚 *[PENPOT PLUGINS] Error deploying API documentation.*
📄 Triggered from ref: `${{ inputs.gh_ref }}`
🔗 Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
@infra
command: deploy --config wrangle-penpot-plugins-api-doc.toml --name ${{ env.WORKER_NAME }}

View File

@@ -36,11 +36,7 @@
- Fix exception on uploading large fonts [Github #8135](https://github.com/penpot/penpot/pull/8135)
- Fix unhandled exception on open-new-window helper [Github #7787](https://github.com/penpot/penpot/issues/7787)
- Fix incorrect handling of input values on layout gap and padding inputs [Github #8113](https://github.com/penpot/penpot/issues/8113)
- Fix several race conditions on path editor [Github #8187](https://github.com/penpot/penpot/pull/8187)
- Fix app freeze when introducing an error on a very long token name [Taiga #13214](https://tree.taiga.io/project/penpot/issue/13214)
- Fix import a file with shadow tokens [Taiga #13229](https://tree.taiga.io/project/penpot/issue/13229)
- Fix allow spaces on token description [Taiga #13184](https://tree.taiga.io/project/penpot/issue/13184)
- Fix error when creating a token with an invalid name [Taiga #13219](https://tree.taiga.io/project/penpot/issue/13219)
## 2.12.1

View File

@@ -873,8 +873,11 @@
(import-storage-objects cfg)
(let [files (get manifest :files)
result (reduce (fn [result file]
result (reduce (fn [result {:keys [id] :as file}]
(let [name' (get file :name)
name' (if (map? name)
(get name id)
name')
file (assoc file :name name')]
(conj result (import-file cfg file))))
[]

View File

@@ -97,12 +97,9 @@
(def token-types
(into #{} (keys token-type->dtcg-token-type)))
(def token-name-validation-regex
#"^[a-zA-Z0-9_-][a-zA-Z0-9$_-]*(\.[a-zA-Z0-9$_-]+)*$")
(def token-name-ref
[:re {:title "TokenNameRef" :gen/gen sg/text}
token-name-validation-regex])
#"^(?!\$)([a-zA-Z0-9-$_]+\.?)*(?<!\.)$"])
(def ^:private schema:color
[:map

View File

@@ -1462,12 +1462,11 @@ Will return a value that matches this schema:
(def ^:private schema:dtcg-node
[:schema {:registry
{::simple-value
[:or :string :int :double ::sm/boolean]
[:or :string :int :double]
::value
[:or
[:ref ::simple-value]
[:vector ::simple-value]
[:vector [:map-of :string ::simple-value]]
[:map-of :string [:or
[:ref ::simple-value]
[:vector ::simple-value]]]]}}

View File

@@ -9,7 +9,7 @@ This guide explains how to get your own Penpot instance, running on a machine yo
to test it, use it by you or your team, or even customize and extend it any way you like.
If you need more context you can look at the <a
href="https://community.penpot.app/t/self-hosting-penpot-i/2336" target="_blank">post
href="https://penpot.app/blog/how-to-self-host-penpot/" target="_blank">post
about self-hosting</a> in Penpot community.
<strong>The experience stays the same, whether you use

View File

@@ -110,7 +110,7 @@ test("Update an already created text shape by prepending text", async ({
await workspace.textEditor.stopEditing();
});
test.skip("Update an already created text shape by inserting text in between", async ({
test("Update an already created text shape by inserting text in between", async ({
page,
}) => {
const workspace = new WorkspacePage(page, {
@@ -151,7 +151,7 @@ test("Update a new text shape appending text by pasting text", async ({
await workspace.textEditor.stopEditing();
});
test.skip("Update a new text shape prepending text by pasting text", async ({
test("Update a new text shape prepending text by pasting text", async ({
page,
context,
}) => {

View File

@@ -70,22 +70,20 @@
(= (-> content last :command) :move-to))
(into [] (take (dec (count content)) content))
content)]
(st/set-content state content)))
(-> state
(st/set-content content))))
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
local (get state :workspace-local)
id (get local :edition)
objects (dsh/lookup-page-objects state page-id)]
objects (dsh/lookup-page-objects state page-id)
id (dm/get-in state [:workspace-local :edition])
old-content (dm/get-in state [:workspace-local :edit-path id :old-content])
shape (st/get-path state)]
;; NOTE: we proceed only if the shape is present on the
;; objects, if shape is a ephimeral drawing shape, we should
;; do nothing
(when-let [shape (get objects id)]
(when-let [old-content (dm/get-in local [:edit-path id :old-content])]
(let [new-content (get shape :content)
changes (generate-path-changes it objects page-id shape old-content new-content)]
(rx/of (dch/commit-changes changes))))))))))
(if (and (some? old-content) (some? (:id shape)))
(let [changes (generate-path-changes it objects page-id shape old-content (:content shape))]
(rx/of (dch/commit-changes changes)))
(rx/empty)))))))

View File

@@ -8,6 +8,7 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.geom.point :as gpt]
[app.common.types.path :as path]
[app.common.types.path.helpers :as path.helpers]
@@ -288,34 +289,34 @@
(declare stop-path-edit)
(defn start-path-edit
[id]
(ptk/reify ::start-path-edit
ptk/UpdateEvent
(update [_ state]
(let [objects (dsh/lookup-page-objects state)
shape (get objects id)]
edit-path (dm/get-in state [:workspace-local :edit-path id])
content (st/get-path state :content)
state (cond-> state
(cfh/path-shape? objects id)
(st/set-content (path/close-subpaths content)))]
(-> state
(st/set-content (path/close-subpaths (:content shape)))
(update-in [:workspace-local :edit-path id]
(fn [state]
(let [state (if state
(if (= :move (:edit-mode state))
(assoc state :edit-mode :draw)
state)
{:edit-mode :move
:selected #{}
:snap-toggled false})]
(assoc state :old-content (:content shape))))))))
(cond-> state
(or (not edit-path)
(= :draw (:edit-mode edit-path)))
(assoc-in [:workspace-local :edit-path id] {:edit-mode :move
:selected #{}
:snap-toggled false})
(and (some? edit-path)
(= :move (:edit-mode edit-path)))
(assoc-in [:workspace-local :edit-path id :edit-mode] :draw))))
ptk/WatchEvent
(watch [_ _ stream]
(let [stopper (rx/filter #(let [type (ptk/type %)]
(= type ::dwe/clear-edition-mode)
(= type ::start-path-edit))
stream)]
(let [stopper (->> stream
(rx/filter #(let [type (ptk/type %)]
(= type ::dwe/clear-edition-mode)
(= type ::start-path-edit))))]
(rx/concat
(rx/of (undo/start-path-undo))
(->> stream
@@ -324,8 +325,7 @@
(rx/map #(stop-path-edit id))
(rx/take-until stopper)))))))
(defn stop-path-edit
[id]
(defn stop-path-edit [id]
(ptk/reify ::stop-path-edit
ptk/UpdateEvent
(update [_ state]
@@ -335,12 +335,13 @@
(watch [_ _ _]
(rx/of (ptk/data-event :layout/update {:ids [id]})))))
(defn- split-segments
[id {:keys [from-p to-p t]}]
(defn split-segments
[{:keys [from-p to-p t]}]
(ptk/reify ::split-segments
ptk/UpdateEvent
(update [_ state]
(let [content (st/get-path state :content)]
(let [id (st/get-path-id state)
content (st/get-path state :content)]
(-> state
(assoc-in [:workspace-local :edit-path id :old-content] content)
(st/set-content (-> content
@@ -352,10 +353,10 @@
(rx/of (changes/save-path-content {:preserve-move-to true})))))
(defn create-node-at-position
[params]
[event]
(ptk/reify ::create-node-at-position
ptk/WatchEvent
(watch [_ state _]
(let [id (st/get-path-id state)]
(rx/of (dwsh/update-shapes [id] path/convert-to-path)
(split-segments id params))))))
(split-segments event))))))

View File

@@ -36,12 +36,10 @@
(defn- hide-popover
[node]
(when (and (some? node)
(fn? (.-hidePopover node)))
(dom/unset-css-property! node "block-size")
(dom/unset-css-property! node "inset-block-start")
(dom/unset-css-property! node "inset-inline-start")
(.hidePopover ^js node)))
(dom/unset-css-property! node "block-size")
(dom/unset-css-property! node "inset-block-start")
(dom/unset-css-property! node "inset-inline-start")
(.hidePopover ^js node))
(defn- calculate-placement-bounding-rect
"Given a placement, calcultates the bounding rect for it taking in

View File

@@ -16,7 +16,7 @@
(def context (mf/create-context nil))
(mf/defc form-input*
[{:keys [name trim] :rest props}]
[{:keys [name] :rest props}]
(let [form (mf/use-ctx context)
input-name name
@@ -33,7 +33,7 @@
(mf/deps input-name)
(fn [event]
(let [value (-> event dom/get-target dom/get-input-value)]
(fm/on-input-change form input-name value trim))))
(fm/on-input-change form input-name value true))))
props
(mf/spread-props props {:on-change on-change

View File

@@ -11,7 +11,6 @@
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.types.color :as cl]
[app.common.types.token :as cto]
[app.common.types.tokens-lib :as ctob]
[app.main.data.style-dictionary :as sd]
[app.main.data.tinycolor :as tinycolor]
@@ -52,15 +51,12 @@
;; Both variants provide identical color-picker and text-input behavior, but
;; differ in how they persist the value within the forms nested structure.
(defn- resolve-value
[tokens prev-token token-name value]
(let [valid-token-name?
(and (string? token-name)
(re-matches cto/token-name-validation-regex token-name))
token
(let [token
{:value value
:name (if (or (not valid-token-name?) (str/blank? token-name))
:name (if (str/blank? token-name)
"__PENPOT__TOKEN__NAME__PLACEHOLDER__"
token-name)}

View File

@@ -50,13 +50,9 @@
(defn- resolve-value
[tokens prev-token token-name value]
(let [valid-token-name?
(and (string? token-name)
(re-matches cto/token-name-validation-regex token-name))
token
(let [token
{:value (cto/split-font-family value)
:name (if (or (not valid-token-name?) (str/blank? token-name))
:name (if (str/blank? token-name)
"__PENPOT__TOKEN__NAME__PLACEHOLDER__"
token-name)}

View File

@@ -8,7 +8,6 @@
(:require
[app.common.data :as d]
[app.common.files.tokens :as cft]
[app.common.types.token :as cto]
[app.common.types.tokens-lib :as ctob]
[app.main.data.style-dictionary :as sd]
[app.main.data.workspace.tokens.format :as dwtf]
@@ -141,13 +140,9 @@
(defn- resolve-value
[tokens prev-token token-name value]
(let [valid-token-name?
(and (string? token-name)
(re-matches cto/token-name-validation-regex token-name))
token
(let [token
{:value value
:name (if (or (not valid-token-name?) (str/blank? token-name))
:name (if (str/blank? token-name)
"__PENPOT__TOKEN__NAME__PLACEHOLDER__"
token-name)}
tokens

View File

@@ -230,7 +230,6 @@
:placeholder (tr "workspace.tokens.enter-token-name" token-title)
:max-length max-input-length
:variant "comfortable"
:trim true
:auto-focus true}]
(when (and warning-name-change? (= action "edit"))

View File

@@ -106,20 +106,17 @@
(defn stop-propagation
[^js event]
(when (and (some? event)
(fn? (.-stopPropagation event)))
(when event
(.stopPropagation event)))
(defn stop-immediate-propagation
[^js event]
(when (and (some? event)
(fn? (.-stopImmediatePropagation event)))
(when event
(.stopImmediatePropagation event)))
(defn prevent-default
[^js event]
(when (and (some? event)
(fn? (.-preventDefault event)))
(when event
(.preventDefault event)))
(defn get-target

View File

@@ -7,16 +7,15 @@
(ns app.util.keyboard
(:require
[app.config :as cfg]
[app.util.dom :as dom]
[cuerdas.core :as str]))
(defrecord KeyboardEvent [type key shift ctrl alt meta mod editing native-event]
Object
(preventDefault [_]
(dom/prevent-default native-event))
(.preventDefault native-event))
(stopPropagation [_]
(dom/stop-propagation native-event)))
(.stopPropagation native-event)))
(defn keyboard-event?
[o]

View File

@@ -0,0 +1,4 @@
name = "penpot-plugins-api-doc"
compatibility_date = "2025-01-01"
assets = { directory = "dist/doc" }