23998 Commits

Author SHA1 Message Date
Eva Marco
2e13bea1c4 🐛 Fix validation error when turning a component into a variant
transform-in-variant (Ctrl+K on a component) runs a chain of events,
each one committing its own changes. It set the variant-id on the main
instance before setting it on the component, so the shape validation
of that step saw them out of sync and rejected the change. The next
steps then failed too, as the main instance was never a variant.

Set the variant-id on the component first, and give the main instance
an empty variant-name, which is what the validator expects while the
variant has no properties yet.

AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:56:19 +02:00
Eva Marco
387f0cb5dc 🐛 Skip shape validation in the page index worker
The page index worker applies the same changes to its own copy of the
pages, which has no file id and no components. :validate-shapes changes
then always failed there, so the worker logged "error updating page
index" and stopped updating the snap and selection indexes of that page
after any validated change. Drop :validate-shapes changes before
applying them in the worker.

AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:56:19 +02:00
Eva Marco
ff58d8c121 🔧 Add tests for restoring variants and property chains
Cover the callers of the variant generators that had no tests with the
new validation: restoring a deleted variant into its container, restoring
it after its container was deleted, and adding a property and then
setting its value, as the workspace properties panel does. Each case
runs with valid data and expects no validation error on JS.

AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 16:52:35 +02:00
Eva Marco
2fc6e33f17 🔧 Validate the enclosing component when relocating a variant
When generate-relocate moves a variant inside a component, the variant
is no longer a root, so relocate left it out and validated nothing in
its place. Validate the root of the enclosing component instead. The
workspace does not allow this move, but relocate can be called
directly.

Document that the default call of generate-make-shapes-no-variant
requires the shapes to be outside their variant container.

Add tests for moving a variant into another container, and into a
component with a corrupted root.

AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 16:50:24 +02:00
Eva Marco
42da392e47 ⚡ Validate only the variant container in variant generators
Validating a variant container already checks each of its main
instances, so listing the mains next to it repeated the work. Each id
costs a pass over the whole page, so a variant with N components cost
N+1 passes per call, and each error was reported twice.

The generators in variant_properties now validate only the container.
generate-update-property-value and generate-set-variant-error fall back
to the main instance when the component is not a variant. Before, they
emitted a nil id, which fails the :validate-shapes schema.

Add a test that generate-set-variant-error on a component that is not a
variant produces valid changes.

AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 16:45:39 +02:00
Eva Marco
26102fb412 🔧 Fix false validation error when pasting a variant
duplicate-variant calls generate-make-shapes-variant before it moves the
new shape into the target container. When a variant is pasted into a
different variant container, the new shape already has the target
container's data but still sits in the old one, so the validation in
generate-make-shapes-variant reported errors on valid data.

Pass :skip-validation? to generate-make-shapes-variant, and validate the
target container once the shape is inside it. That also covers the
pasted shape, which the closing validation of
generate-duplicate-changes missed.

Add tests for pasting a variant into another container and for
duplicating it inside the same container.

AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 16:38:31 +02:00
Eva Marco
08f9fca672 🔧 Validate shapes after moving them into a variant
generate-make-shapes-variant now validates the new variants and their
variant container, and accepts a :skip-validation? option.

generate-relocate calls it before the shapes are inside the container,
so it passes :skip-validation?. Relocate already validates the new
container once the shapes are moved.

Add tests that corrupt the new variant or the container and expect a
validation error, and a test for :skip-validation?.

AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 16:16:45 +02:00
Eva Marco
8e306b8e24 🔧 Validate shapes after removing them from a variant
generate-make-shapes-no-variant now validates the shapes and their old
variant containers, and accepts a :skip-validation? option.

generate-relocate calls it before moving the shapes, while they are
still inside the container. Validating the container at that point
reported :main-instance-not-a-variant on valid data. Relocate now passes
:skip-validation? and validates at the end: the old and new variant
containers, and the moved variants when they end up outside any
component. Inside a component they are no longer roots, and the
validator can't check them on their own.

Add tests for the function and for moving a variant out of its
container, with valid and corrupted data.

AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 16:13:40 +02:00
Eva Marco
c02b75a37e 🔧 Validate shapes after adding a variant property
generate-add-new-property now validates the main instances and the
variant container. Add a :skip-validation? option to it.

generate-make-shapes-variant calls it several times before the new
shapes become variants. Validating the container at that point reported
:main-instance-not-a-variant on valid data, so it now passes
:skip-validation? and will validate once the shapes are variants.

Add tests that corrupt a main instance or the container and expect a
validation error. Add a test that moves into a variant a component whose
name needs more properties, which runs that intermediate path. Register
variants-test in the runner so that it also runs on JS.

AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 16:06:09 +02:00
Eva Marco
4cb36153af 🔧 Validate shapes after reordering variant properties
generate-reorder-variant-poperties now validates the main instances and
the variant container, but only when the reorder changed something, so
a no-op still returns the same changes. Add tests that corrupt a main
instance or the container and expect a validation error.

AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 16:01:26 +02:00
Eva Marco
e625fc8600 🔧 Validate shapes after setting a variant error
generate-set-variant-error now validates the main instance of the
component and its variant container. The validator has no rule for
:variant-error itself, so the new tests corrupt the main instance or the
container and expect a validation error.

AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 15:59:05 +02:00
Eva Marco
94667f5b06 🔧 Validate shapes after updating a variant property value
generate-update-property-value now validates the main instance of the
component and its variant container once the new value is set. Add tests
that corrupt the main instance or the container and expect a
validation error.

AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 15:53:53 +02:00
Eva Marco
79851eef0e 🔧 Fix false validation errors on nested instances and swaps
generate-instantiate-component validated the new instance on its own.
When the parent is inside another component, the new instance is a
nested copy. The validator starts with a :not-component context, so it
reported :nested-copy-not-allowed. Validate the root of the enclosing
component instead, which walks the new copy with the right context.

During a component swap, generate-new-shape-for-swap sets the swap slot
after the instance is created. Validating at instantiation time then
reported :missing-slot. Add a :skip-validation? option to
generate-instantiate-component. The swap sets it and validates the
enclosing root once the swap slot is in place.

These false errors broke 34 common tests on JS.

AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 14:31:12 +02:00
Eva Marco
84daab304a 💄 Fix indentation in files/variant.cljc
AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 14:31:05 +02:00
Eva Marco
b46bcc9207 🔧 Validate variant containers after property changes
apply-changes-local replays the pending redo changes on a local copy of
the data, so that later builder calls can read up-to-date values. It
replayed :validate-shapes too, so the validator ran on that copy, which
has no real file id and no libraries. Any chain of two generators that
apply local changes then failed with false errors, such as
:component-not-found. Skip :validate-shapes when applying changes
locally.

Add the variant container to the shapes that
generate-update-property-name and generate-remove-property validate.
Validating only the main instances misses errors that only the container
check finds, such as siblings with different property names.

Register variant-properties-test in the runner so that it runs on JS,
where validation takes place. Add tests that corrupt a main instance or
the container and expect a validation error. Remove two debug prn calls
from the validator.

AI-assisted-by: claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 14:26:28 +02:00
Andrés Moya
5c80841143 🔧 Add tests and validations to variant functions 2026-09-29 13:33:40 +02:00
Andrés Moya
0cb10a55e2 💄 Rename props -> properties 2026-09-29 13:30:10 +02:00
Andrés Moya
5868ad0042 🔧 Validate changes immediately after processing them 2026-09-29 13:30:05 +02:00
David Barragán Merino
eb2576b8c0 👷 Run plugins package deploy inside devenv container
Parallel deploy jobs on the shared self-hosted host raced on
/home/runner/setup-pnpm (ENOTEMPTY / missing tarball errors).
Use penpotapp/devenv, which already ships the Node and pnpm versions
pinned in develop, and mount a persistent pnpm store from the host
instead of pnpm/setup + actions/cache.

Signed-off-by: David Barragán Merino <david.barragan@kaleidos.net>
2026-09-28 22:01:22 +02:00
Miguel de Benito Delgado
efbb554af1
♻️ Move use-shape into app.common.render_wasm (#11917)
- Introduces a new ns since there wasn't a suitable one
- Simplifies serialize-shapes-batch! and allows usage outside the frontend
2026-09-28 18:19:55 +02:00
David Barragán Merino
494d60a671 🐛 Fix script injection in GitHub Actions workflows
Values coming from `${{ }}` expressions were interpolated directly into
`run:` scripts, so GitHub substituted them into the shell source before
bash parsed it. A commit title containing a double quote broke the
"Write step summary" step of the bundle build with a syntax error, and
the same pattern allowed arbitrary command execution on the
self-hosted runners.

Pass every expression used inside `run:` through step/job `env:` and
reference it as a quoted shell variable instead. Use the runner's
default variables (GITHUB_RUN_ID, GITHUB_REPOSITORY, ...) where the
value comes from the `github` context.

Also validate `plugin_name` in plugins-deploy-package.yml against
`^[a-z0-9][a-z0-9-]*$`, since it is free-form and reaches paths,
worker names, GITHUB_ENV and action inputs.

Affected workflows: build-bundle, build-docker,
build-docker-admin-console, plugins-deploy-package,
plugins-deploy-api-doc, plugins-deploy-styles-doc, release, tests-e2e.

Signed-off-by: David Barragán Merino <david.barragan@kaleidos.net>
2026-09-28 16:59:03 +02:00
Andrey Antukh
f9b8f1ba75 Merge remote-tracking branch 'origin/staging' into develop 2026-09-28 10:31:20 +02:00
Andrey Antukh
370519937d Merge remote-tracking branch 'origin/develop' into develop 2026-09-28 10:27:20 +02:00
girafic
7e0b65f291
🐛 Hide the custom resize icon of the plugin modal in Firefox (#11798)
Firefox draws its own resize grip for a box with `resize: both` and,
unlike Chrome and Safari, gives no way to hide it: `::-webkit-resizer`
is ignored. The plugin modal therefore showed two grips in its
bottom-right corner, its own icon and the one from the browser.

Show the custom icon only where the browser grip can be hidden. In
Firefox the native grip is now the only one.

Closes #11795
2026-09-28 10:19:35 +02:00
Andrey Antukh
1349d1ef2d 🌐 Rehash and validate translation files 2026-09-28 10:15:48 +02:00
Alexis Morin
88984ee03e
🌐 Add translations for: French (Canada)
Currently translated at 95.3% (2169 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fr_CA/
2026-09-28 08:14:12 +00:00
Anonymous
a45eaa2b3c
🌐 Add translations for: French (Canada)
Currently translated at 95.3% (2169 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fr_CA/
2026-09-28 08:14:11 +00:00
VKing9
4eeb652893
🌐 Add translations for: Hindi
Currently translated at 76.7% (1746 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/hi/
2026-09-28 08:14:10 +00:00
AntonPalmqvist
187369c393
🌐 Add translations for: Swedish
Currently translated at 98.0% (2230 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/sv/
2026-09-28 08:14:09 +00:00
Anonymous
7aaef298a3
🌐 Add translations for: Swedish
Currently translated at 98.0% (2230 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/sv/
2026-09-28 08:14:08 +00:00
Stephan Paternotte
d18b1285a4
🌐 Add translations for: Dutch
Currently translated at 98.0% (2230 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/nl/
2026-09-28 08:14:07 +00:00
Anonymous
e0c23951a0
🌐 Add translations for: Dutch
Currently translated at 98.0% (2230 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/nl/
2026-09-28 08:14:06 +00:00
Anonymous
151f6d29e9
🌐 Add translations for: Korean
Currently translated at 76.7% (1747 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ko/
2026-09-28 08:14:04 +00:00
Anonymous
623b615cdc
🌐 Add translations for: Ukrainian (ukr_UA)
Currently translated at 78.9% (1795 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ukr_UA/
2026-09-28 08:14:03 +00:00
Anonymous
4a4217ef7c
🌐 Add translations for: Italian
Currently translated at 81.9% (1864 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/it/
2026-09-28 08:14:02 +00:00
Danial Shirali
e13ef345f3
🌐 Add translations for: Persian
Currently translated at 98.0% (2230 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fa/
2026-09-28 08:14:01 +00:00
Andy Li
da273234e1
🌐 Add translations for: Chinese (Traditional Han script)
Currently translated at 97.9% (2228 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/zh_Hant/
2026-09-28 08:14:00 +00:00
Anonymous
50b427b4ff
🌐 Add translations for: Hebrew
Currently translated at 83.8% (1907 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/he/
2026-09-28 08:13:58 +00:00
Anonymous
e9c9761a9f
🌐 Add translations for: German
Currently translated at 76.0% (1729 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/de/
2026-09-28 08:13:57 +00:00
DoubleCat
dd0690124e
🌐 Add translations for: Chinese (Simplified Han script)
Currently translated at 90.0% (2049 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/zh_Hans/
2026-09-28 08:13:56 +00:00
Oğuz Ersen
42ae277979
🌐 Add translations for: Turkish
Currently translated at 98.0% (2230 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/tr/
2026-09-28 08:13:55 +00:00
Anonymous
628155b6b0
🌐 Add translations for: Turkish
Currently translated at 98.0% (2230 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/tr/
2026-09-28 08:13:54 +00:00
Anonymous
bfa9575bb4
🌐 Add translations for: Russian
Currently translated at 64.1% (1459 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/ru/
2026-09-28 08:13:53 +00:00
Surfoo
1c69fa0c32
🌐 Add translations for: French
Currently translated at 98.0% (2230 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fr/
2026-09-28 08:13:52 +00:00
Anonymous
b1d4b4526f
🌐 Add translations for: French
Currently translated at 98.0% (2230 of 2275 strings)

Translation: Penpot/frontend
Translate-URL: https://hosted.weblate.org/projects/penpot/frontend/fr/
2026-09-28 08:13:51 +00:00
Andrey Antukh
38b33aba53 Merge remote-tracking branch 'weblate/develop' into develop 2026-09-28 09:59:20 +02:00
Alonso Torres
a31409617f
🐛 Fix loop with context menu (#11891) 2026-09-28 09:08:28 +02:00
Alonso Torres
2b8344d3a8
🐛 Fix delete on curve handlers (#11896) 2026-09-28 09:06:47 +02:00
Eva Marco
20c818661d
♻️ Add DS tooltip to token pills" (#11900)
* 🐛 Fix can-edit permission wiring for token pills

* ✨ Use DS tooltip component in token pill

* 🎉 Add playwright test

* 🐛 Fix tests
2026-09-28 08:54:12 +02:00
Eva Marco
7e3f779d8c
🎉 Add tokens to the canvas (#11923)
* ✨ Show color tokens toggle on canvas background picker

* 🐛 Apply token click on canvas background with no shape selected

* ✨ Apply and persist color tokens on canvas background

* 🌐 Translate canvas background section label
2026-09-28 08:53:42 +02:00