13619 Commits

Author SHA1 Message Date
Eva Marco
3708cf31d4
🐛 Fix stroke cap selects (#10631) 2026-07-10 11:05:09 +02:00
Andrey Antukh
3400d6afbb
🐛 Fix too much recursion when clicking shape in comments mode (#10622)
* 🐛 Fix too much recursion when clicking shape in comments mode

Remove `deselect-all` from `handle-interrupt` in comments mode. The
`select-shape` event emits `:interrupt` which the comments stream
watcher routes to `handle-interrupt`. In comments mode, calling
`deselect-all` cleared the selection and emitted a competing
`rt/nav`, creating a synchronous recursion cycle in the potok store
that overflowed the JS call stack.

Fixes #10620

AI-assisted-by: opencode

* 🐛 Add unit tests for comments handle-interrupt

Make `handle-interrupt` public (defn- → defn) and add 4 tests covering
each branch: draft thread, open thread, comments mode, and noop.

AI-assisted-by: opencode
2026-07-09 18:04:05 +02:00
Alonso Torres
d6c50cc40b
🐛 Fix problems with plugins api setPluginData (#10632) 2026-07-09 18:00:26 +02:00
Andrey Antukh
28fd798c52
🐛 Fix crash with degenerate selrect in text pipeline (#10618)
Guard remaining text pipeline locations that accessed :selrect directly
against nil/zero-dimension selrects by using safe-size-rect, which
provides a 4-level fallback chain (selrect -> points -> shape fields ->
empty 0.01x0.01 rect).

Fixes:
- fix-position in viewport_texts_html.cljs: replaced dm/get-prop
  :selrect with ctm/safe-size-rect for both old and new shape
- assoc-position-data in modifiers.cljs: replaced (:selrect ...)
  with ctm/safe-size-rect for delta computation
- change-orientation-modifiers in modifiers.cljc: replaced raw
  :selrect access with safe-size-rect for scale and origin computation

Closes #10617

AI-assisted-by: mimo-v2.5-pro
2026-07-09 11:03:06 +02:00
Andrey Antukh
47a3158602
🐛 Fix component variant panel crash with mismatched property counts (#10616)
Use `get` instead of `nth` to avoid index-out-of-bounds when a selected
component copy has fewer variant properties than the first component in
the selection.

Closes #10615

AI-assisted-by: deepseek-v4-pro
2026-07-09 11:01:08 +02:00
Andrey Antukh
f2460eee29
🐛 Fix Draft.js selection offset DOMException on text editor re-render (#10608)
Clamp selection offset to node length in setDraftEditorSelection to
prevent DOMException when Draft.js SelectionState offset exceeds the
actual DOM text node length. This can happen during spellcheck, IME
composition, or race conditions during React re-renders.

Updates @penpot/draft-js to commit 09a33e0a which includes the fix
in addPointToSelection and addFocusToSelection.

Fixes #10607

AI-assisted-by: mimo-v2.5-pro
2026-07-09 10:59:40 +02:00
Elena Torró
8ac2e8c8a8
🐛 Fix sidebar scroll to shape (#10600) 2026-07-08 20:38:16 +02:00
Elena Torró
d656d342fe
🐛 Fix text selrect size (#10566)
* 🐛 Fix text selrect size

* 🐛 Fix blinks on complex files

---------

Co-authored-by: Belén Albeza <belen@hey.com>
2026-07-08 13:56:58 +02:00
Eva Marco
ff0d56a86e
🐛 Fix blur menu width (#10575) 2026-07-08 10:06:23 +02:00
Juan de la Cruz
8b16bb8874
Add new slides content for 2.17 release (#10577)
*  Add new slides content for 2.17 release

* 📎 Fix linter issues

---------

Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-07-08 09:39:38 +02:00
Alonso Torres
7655f854a4
Improved api test suite (#10533)
* 🐛 Fix plugins api issues

* 🐛 Fix problem with text weight

* 🐛 Fix api problems

*  Updated plugins test suite

* 🐛 Referential integrity tests

*  Add resetOverrides method

* 🐛 Fix plugins components structure poluting
2026-07-07 16:12:12 +02:00
Dr. Dominik Jain
c88d9f568b
🐛 Preserve component order when combining components as variants (#10562) 2026-07-06 16:49:29 +02:00
Alonso Torres
2dfb1046f7
🐛 Fix problem with rotations crashing (#10560) 2026-07-06 11:56:46 +02:00
Luis de Dios
e5d3ea14d1
🐛 Fix size badge shows "x" instead of dimensions when creating a path (#10550) 2026-07-03 14:58:43 +02:00
Luis de Dios
d795a1f110
Manage rotation and color of selection size badge (#10393)
*  Rotate and move size badge when shape is rotated

* 🐛 Fix wrong text color in selection size badge

*  Add tests

* ♻️ Extract common constants
2026-07-02 14:59:33 +02:00
RenzoMXD
1c9ab691e6 🐛 Plugin API theme.addSet/removeSet accept proxy or set ID
Signed-off-by: RenzoMXD <170978465+RenzoMXD@users.noreply.github.com>

🐛 Preserve validation errors for theme set APIs

Signed-off-by: RenzoMXD <170978465+RenzoMXD@users.noreply.github.com>

Co-authored-by: Alonso Torres <alonso.torres@kaleidos.net>
2026-07-02 13:32:17 +02:00
Filip Sajdak
5b7447fbe4 🐛 Accept delay 0 in plugin API interaction setter
The InteractionProxy `delay` setter rejected `0` via `(not (pos? value))`,
so an immediate after-delay interaction (`interaction.delay = 0`) was
refused. The model allows it: `set-delay`
(common/.../shape/interactions.cljc) only asserts `check-safe-int`, with
no positivity constraint, and `safe-int` permits 0.

Replace the guard with `(or (not (sm/valid-safe-int? value)) (neg? value))`:
it allows 0 and positive integers, rejects negatives, and rejects
non-integers cleanly (the previous `number?` check let fractional values
through, which then failed the model's `check-safe-int` assertion
downstream).

Adds a regression test (delay round-trips a positive value, then 0).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Filip Sajdak <filip.sajdak@siili.com>
2026-07-02 13:32:17 +02:00
Filip Sajdak
1c5c6ee072 🐛 Accept fractional border radius in plugin API shape setters
The ShapeProxy `borderRadius` setters (`borderRadius` and the four
per-corner variants) validated with `sm/valid-safe-int?`, so a fractional
radius (e.g. `shape.borderRadius = 7.5`) was rejected as invalid. The data
model types `:r1`-`:r4` as `::sm/safe-number` (shape.cljc), the radius
sidebar input only constrains `min 0` (not integer), and `set-radius-*`
store the value verbatim — so the plugin API was stricter than the model.
Same class of defect as the merged #9780.

Switch those 5 guards to `sm/valid-safe-number?`, keeping the existing
non-negative guard on the all-corners setter. Integer-only setters in the
file (`getRange` bounds, `setParentIndex`) keep `valid-safe-int?`.

Adds a regression test asserting fractional radius values are accepted
(with throwValidationErrors enabled).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Filip Sajdak <filip.sajdak@siili.com>
2026-07-02 13:32:17 +02:00
Filip Sajdak
c7ee54e849 🐛 Accept fractional gap and padding in plugin API layout setters
The flex and grid layout proxies validated `rowGap`, `columnGap` and the
four padding setters with `sm/valid-safe-int?`, so a fractional value
(e.g. `flex.rowGap = 10.5`) was rejected as invalid. The data model types
`:row-gap`/`:column-gap` and `:p1`-`:p4` as `::sm/safe-number`
(layout.cljc), and the sidebar accepts decimals, so the plugin API was
stricter than the model — the same class of defect as the merged #9780.

Switch those 16 gap/padding guards (8 in flex.cljs, 8 in grid.cljs) to
`sm/valid-safe-number?`, matching the model and the predicate already used
by the flex-element setters in the same file. Integer-only setters
(`zIndex`, grid track indices/counts and cell positions/spans) keep
`valid-safe-int?`. Also fixes a `:righPadding` typo in two grid
rightPadding error branches.

Adds a regression test asserting fractional gap/padding values are
accepted (with throwValidationErrors enabled) for both flex and grid.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Filip Sajdak <filip.sajdak@siili.com>
2026-07-02 13:32:17 +02:00
mvanhorn
355f7acb66 🐛 Make animation optional in plugin CloseOverlay type and align overlay typings 2026-07-02 13:32:17 +02:00
mvanhorn
ab623cc02d 🐛 Make overlay position optional in plugin open-overlay/toggle-overlay interactions 2026-07-02 13:32:17 +02:00
Filip Sajdak
76070008c2 🐛 Fix plugin API board.guides invalid-schema on set/clear
Setting or clearing `board.guides` from a plugin threw a malli
`:malli.core/invalid-schema` for every value, including `[]`. Causes:

- `shape.cljs` validated against `[:vector ::ctg/grid]`, but the
  `:app.common.types.grid/grid` reference is no longer registered
  (direct schemas replaced the namespaced-keyword registrations). Use
  the direct var `ctg/schema:grid`, matching every other setter.
- `parser.cljs` `parse-frame-guide` returned the `parse-frame-guide-column`
  / `parse-frame-guide-row` fns instead of calling them with the guide,
  so column/row guides parsed to a vector containing a function.
- `parse-frame-guide-square` used `parse-frame-guide-column-params`
  instead of the dedicated `parse-frame-guide-square-params`.

Adds a regression test parsing column/square guides and validating the
result (and an empty vector) against `ctg/schema:grid`.

Fixes #9773

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Filip Sajdak <filip.sajdak@siili.com>
2026-07-02 13:32:17 +02:00
Filip Sajdak
8fe835a9cc 🐛 Surface real plugin errors instead of bare "Value not valid"
The plugin proxy `:on-error` handler funneled every throwable through
`handle-error`, which only produced a message for malli ExceptionInfo
carrying `::sm/explain`. Two paths lost the real cause and rendered the
unhelpful "[PENPOT PLUGIN] Value not valid. Code: :error":

- A plain JS error (TypeError, etc.) is not an ExceptionInfo, so
  `(ex-data cause)` is nil and the message bound to nil; the real
  `.-message` only reached the host-page console, invisible to the
  plugin sandbox.
- A malli explain whose errors flatten to nothing made `error-messages`
  return "", which rendered as "Value not valid: . Code: :error".

`error-messages` now returns nil (not "") when there is nothing to
render, and `handle-error` falls back to the raw explain, then to the
throwable's `ex-message`/`str`, so a useful message always surfaces.
Working cases (well-formed explain) are unchanged.

Adds regression tests for the plain-JS-error path, the empty-explain
path, and the `error-messages` nil contract.

Fixes #9692

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Filip Sajdak <filip.sajdak@siili.com>
2026-07-02 13:32:17 +02:00
Eva Marco
f1f5a30624
🐛 Fix alignment selector for strokes (#10532) 2026-07-02 13:01:58 +02:00
Elena Torró
28b5371901
🔧 Improve text strokes in texts with emoji (#10519) 2026-07-01 18:10:46 +02:00
Alejandro Alonso
f25317ac47
🐛 Fix text inner stroke fill seam by compositing fill inside SrcIn (#10509)
* 🐛 Fix text inner stroke fill seam by compositing fill inside SrcIn

* 🔧 Update e2e Playwright screenshots
2026-07-01 16:24:23 +02:00
Andrey Antukh
6cc2c403c4 ⬆️ Update dependencies 2026-07-01 14:45:41 +02:00
Andrey Antukh
44d33a0c80 Merge remote-tracking branch 'origin/staging' into staging 2026-07-01 14:41:01 +02:00
Andrey Antukh
77a8677b60 Merge remote-tracking branch 'origin/main' into staging 2026-07-01 14:40:36 +02:00
Eva Marco
e6a341ff30
🐛 Fix text layout item menu (#10516) 2026-07-01 14:39:34 +02:00
Andrey Antukh
1006efc571 🐛 Fix translation strings 2026-07-01 14:38:08 +02:00
Eva Marco
04254c9fd1
🐛 Fix token tooltips (#10515) 2026-07-01 14:30:18 +02:00
Eva Marco
665e8e018e
🐛 Fix overlay position grid (#10512) 2026-07-01 13:40:12 +02:00
Eva Marco
abbd28d101
🐛 Fix long text inside color tooltip (#10511) 2026-07-01 13:38:51 +02:00
Luis de Dios
7e8590b04c
🐛 Fix inspect in workspace displays shape size twice when selecting a shape (#10507) 2026-07-01 13:08:35 +02:00
Elena Torró
c8f586a197
🐛 Fix async text rendering on tiles (#10504) 2026-07-01 11:09:57 +02:00
Alejandro Alonso
05e9c68a74
🐛 Fix preserving empty text fill when editing without changes (#10483) 2026-06-30 17:59:54 +02:00
Eva Marco
920c6d4e76
🐛 Fix token tooltips on numeric-input, color and typography (#10480) 2026-06-30 16:26:49 +02:00
Andrey Antukh
e2b52d88fc ⬆️ Update dependencies 2026-06-30 16:15:30 +02:00
Luis de Dios
28afe223f4
🐛 Invitations to a team can be sent to existing members without displaying any error (#10489)
* 🐛 Fix team invitations can be sent to existing members without displaying any error

*  Add tests
2026-06-30 15:39:59 +02:00
Alonso Torres
8823f7ac4d
Make v2 plugins default throw on error (#10433) 2026-06-30 14:50:50 +02:00
Alonso Torres
ca81776d04
🐛 Fix problems when dragging frame with comments (#10460)
* 🐛 Fix undo frame position not undoing comments

* 🐛 Fix problem with hover capturing dragging event

* 🐛 Fix watch updates for comment bubbles

* 🐛 Fix "Maximum update depth" crash on SVG shape transforms

* 🐛 Fix comment geometry problems
2026-06-30 13:33:47 +02:00
Alonso Torres
f993f203bd
🐛 Fix problems with plugins API (#10412)
*  Adds static dispatch safe stubs in tests

* 🐛 Fix shapesColors metadata key to match ColorShapeInfo

* 🐛 Fix CommentThread.remove rejecting the owner's own threads

* 🐛 Fix page.removeCommentThread throwing on a spurious Promise

*  Implement ShapeBase.swapComponent in the plugin API

*  Expose File.revn in the plugin API

* 🐛 Fix FileVersion.createdAt calling Luxon method on a js/Date

* 🐛 Fix plugin font/typography application to text and ranges

* 🐛 Default plugin overlay interaction position for non-manual types

* 🐛 Fix plugin interaction setters passing an id-only shape

* 🐛 Fix grid addColumnAtIndex rejecting valid track types

* 🐛 Expose libraryId on library color/typography/component proxies

*  Implement LibraryTypography.setFont in the plugin API

* 🐛 Fix typography.applyToTextRange reading unexposed range bounds

* 🐛 Fix utils.geometry.center argument mismatch

* 🐛 Fix localStorage.removeItem calling getItem

* 🐛 Fix shape backgroundBlur proxy key casing

* 🐛 Report boolean shape type as 'boolean' in the plugin API

* 🐛 Return the resulting paths from plugin flatten

* 🐛 Make plugin z-order methods act on the target shape

* 🐛 Make is-variant-container? return a boolean

*  Implement Group.isMask in the plugin API

* 🐛 Return a shape proxy from TextRange.shape

* 🐛 Return the duplicated set from TokenSet.duplicate

* 🐛 Fix theme addSet/removeSet reading set name with a keyword

* 🐛 Accept string fontFamilies token value in the plugin API

* 🐛 Fix combineAsVariants ignoring the passed component ids

* 🐛 Fix board removeRulerGuide ignoring its argument

* 🐛 Fix board guides setter schema and parser

* 🐛 Avoid 0-byte allocation when syncing empty grid tracks

* 🐛 Validate grid track indices in the plugin API

* 🐛 Return null for empty input in group() and centerShapes()

* 🐛 Return TokenTypographyValue[] from a typography token's resolvedValue

* 🐛 Return TokenShadowValue[] from a shadow token's resolvedValue

* 🐛 Return string[] from a fontFamilies token's resolvedValue

* 🐛 Clear mutually-exclusive reps when setting LibraryColor gradient/image

* 🐛 Add readonly tags to types, deprecate Image type

* 📚 Update plugins changelog
2026-06-29 17:32:15 +02:00
Alejandro Alonso
99638fa60c
🐛 Fix wasm render playwright tests (#10462)
* 🐛 Fix playwright wasm test for updating canvas background

* 🐛 Fix playwright wasm test for rendering blurs

* 🐛 Fix invisible emoji texts in render-wasm playwright data
2026-06-29 17:03:45 +02:00
Alonso Torres
a47b0122c7
🐛 Fix problem with measures menu (#10445) 2026-06-29 09:24:37 +02:00
Belén Albeza
e9c0982a94
Disable hot swap of render engines (#10444) 2026-06-26 15:04:52 +02:00
Alejandro Alonso
44e39a1008
🐛 Sync WASM viewport when locating board in grid layout editor (#10443) 2026-06-26 14:24:44 +02:00
Eva Marco
6a79383082
🐛 Blur info doesn't show on inspect in certain shapes (#10427)
* 🐛 Blur info doesn't show on inspect in certain shapes

* 🎉 Add test
2026-06-26 14:10:41 +02:00
Belén Albeza
10147b6abd
🐛 Fix pixel grid and board pixel grid shown on top of rulers (#10430)
* 🐛 Fix pixel grid shown on top of rulers

* 🐛 Fix board pixel grid being rendered above rulers
2026-06-26 11:53:11 +02:00
Luis de Dios
8e9fb91959
🐛 Fix view mode is not persisted in color picker (#10369) 2026-06-26 11:38:51 +02:00