21837 Commits

Author SHA1 Message Date
Andrey Antukh
a403175d5c
🐛 Fix TypeError in sd-token-uuid when resolving tokens interactively (#8929)
The backtrace-tokens-tree function used a namespaced keyword :temp/id
which clj->js converted to the JS property "temp/id". The sd-token-uuid
function then tried to access .id on the sd-token top-level object,
which was undefined, causing "Cannot read properties of undefined
(reading uuid)".

Fix by using the existing token :id instead of generating a temporary
one, and read it from sd-token.original (matching sd-token-name pattern).
2026-04-13 11:34:15 +02:00
Aitor Moreno
bb85b312d6
🐛 Fix text editor v1 focus not being handled correctly (#8942) 2026-04-13 10:00:56 +02:00
Dream
78a16d99a9
Add clear artboard guides option to context menu (#8936)
*  Add clear artboard guides option to context menu

Adds a "Clear artboard guides" option to the right-click context menu
when one or more frames with guides are selected. Closes #6987

* ♻️ Address review feedback from niwinz

- Replace deprecated dm/assert! with assert
- Replace (map :id) with d/xf:map-id

Signed-off-by: eureka928 <meobius123@gmail.com>
2026-04-13 09:58:23 +02:00
Dream
8dccb2a427
Make links in comments clickable (#8894)
*  Make links in comments clickable

Detect URLs in comment text and render them as clickable links that
open in a new tab. Extends the existing mention parsing to also split
text elements by URL patterns, handling trailing punctuation and
mixed mention+URL content.

Closes #1602

* 📚 Add changelog entry for clickable links in comments

* 🐛 Fix URL elements dropped in comment input initialization

* 🐛 Keep empty text elements in parse-urls to preserve cursor anchors

The remove filter in parse-urls was stripping empty text elements
produced by str/split at URL boundaries. These elements are needed
as cursor anchor spans in the contenteditable input, without them
ESC keydown and visual layout broke.

Signed-off-by: eureka928 <meobius123@gmail.com>
2026-04-13 09:55:53 +02:00
Eva Marco
6d1a2d449a
🐛 Fix highlight on frames after rename (#8938) 2026-04-13 09:09:03 +02:00
Yamila Moreno
e7e5a19db7
🔧 Prevent draft pr from executing the CI (#8934) 2026-04-10 14:43:29 +02:00
Belén Albeza
eb811621a9 🐛 Fix initializing guards in viewport loading 2026-04-10 13:54:06 +02:00
Andrés Moya
3312bfe62c Force current set as active when resolving tokens in sidebar 2026-04-10 13:33:29 +02:00
Pablo Alba
ef6eeb5693
🐛 Fix variants corner cases with selrect and points (#8882)
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-04-10 11:23:03 +02:00
Marek Hrabe
9785a13e67
🐛 Add webp export format to plugin types (#8870)
* 🐛 Add webp export format to plugin types

Align plugin API typings with runtime export support by including 'webp' in
'Export.type' and updating the exported formats documentation.

Signed-off-by: Marek Hrabe <marekhrabe@me.com>

* 📚 Add plugin-types changelog entry for missing webp export format

Signed-off-by: Marek Hrabe <marekhrabe@me.com>

---------

Signed-off-by: Marek Hrabe <marekhrabe@me.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-04-10 11:22:20 +02:00
Dexterity
240e8ce50c
🐛 Use page name for multi-export downloads (#8874)
* 🐛 Use page name for multi-export downloads

* ♻️ Refactor parameter formatting in asset export function

*  Use page name for multi-export ZIP/PDF downloads [Github #8773]

---------

Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-04-10 11:21:14 +02:00
Dr. Dominik Jain
8101f58651
📚 Add improvements for mcp readme (#8930)
* 📚 Update description of mcp-remote usage

* Use Streamable HTTP endpoint instead of SSE
* Remove redundant global installation

* 📚 Add recommendations on model selection

* 📚 Use new tags in npx launch commands
2026-04-10 10:49:13 +02:00
Xaviju
9e4c8981be
🎉 Duplicate token group (#8886) 2026-04-10 10:42:35 +02:00
Elena Torró
a87552bc45
Merge pull request #8926 from penpot/superalex-wasm-render-performance
🎉 Wasm render performance improvements
2026-04-10 09:11:50 +02:00
Marek Hrabe
a803bde2ff
🐛 Fix plugin modal dragging bugs (#8871)
* 🐛 Fix plugin modal drag and close interactions

Switch plugin modal dragging to pointer-capture semantics from the header so drag state remains stable when crossing iframe boundaries. Prevent drag start from close-button pointerdown and add regression tests for both non-draggable close-button interaction and close-event dispatch.

Signed-off-by: Marek Hrabe <marekhrabe@me.com>

* 📚 Update changelog for plugin modal drag fix

Document plugin modal drag and close-button interaction fixes in the unreleased changelog.

Signed-off-by: Marek Hrabe <marekhrabe@me.com>

* 🐛 Simplify plugin modal drag CSS selection rules

Keep user-select disabled at the modal wrapper level and keep touch-action scoped to the header drag handle to remove redundant declarations while preserving drag behavior.

Signed-off-by: Marek Hrabe <marekhrabe@me.com>

---------

Signed-off-by: Marek Hrabe <marekhrabe@me.com>
2026-04-09 21:13:10 +02:00
Alejandro Alonso
5eebc17ce2 🎉 Support for debugging cache texture 2026-04-09 19:02:14 +02:00
Alejandro Alonso
434e27bbe8 🎉 Improve panning performance 2026-04-09 19:02:14 +02:00
Dexterity
e49b7ce14c
🐛 Fix warnings for unsupported token $type (#8873)
* 🐛 Fix warnings for unsupported token $type

Signed-off-by: Dexterity104 <hatanokanjiro@gmail.com>

* 🐛 Add changelog entry for Github #8790

---------

Signed-off-by: Dexterity104 <hatanokanjiro@gmail.com>
Signed-off-by: Dexterity <173429049+Dexterity104@users.noreply.github.com>
2026-04-09 17:09:19 +02:00
Alejandro Alonso
5c67cd0a4b 🐛 Avoid unnecesary text editor pointer movements 2026-04-09 16:18:58 +02:00
Yamila Moreno
d2050d5331
🔧 Update tests-mcp.yml
Add a more explicit name for a workflow

Signed-off-by: Yamila Moreno <yamila.moreno@kaleidos.net>
2026-04-09 15:38:34 +02:00
Eva Marco
5b78de3594
🐛 Fix selected colors with tokens (#8889) 2026-04-09 14:10:23 +02:00
Xaviju
666313c2c3
🐛 Close expanded tree when switching or creating sets (#8920) 2026-04-09 12:37:29 +02:00
Eva Marco
290f37425f
🐛 Fix id prop on switch component (#8915) 2026-04-09 12:35:34 +02:00
Andrey Antukh
ef39afe9b5 Merge remote-tracking branch 'origin/main' into staging 2026-04-09 12:24:18 +02:00
Pablo Alba
d65f3b5396 Add nitrate api endpoints to get an user profile 2026-04-09 12:10:06 +02:00
Pablo Alba
fe2023dde5 Add nitrate api endpoints to get an user profile 2026-04-09 12:10:06 +02:00
Elena Torró
a88f8f1394
Merge pull request #8918 from penpot/niwinz-main-path-preview-issue
🐛 Fix path drawing preview passing shape instead of content to next-node
2.14.3-RC1
2026-04-09 11:48:58 +02:00
Eva Marco
b0a99b65e4
🐛 Fix highlight on shape after rename (#8890) 2026-04-09 11:27:36 +02:00
Andrey Antukh
388775413e 🐛 Fix path drawing preview passing shape instead of content to next-node
In `preview-next-point`, `st/get-path` was called without extra keys,
which returns the full Shape record. That value was then passed directly
to `path/next-node` as its `content` argument.

`path/next-node` delegates to `impl/path-data`, which only accepts a
`PathData` instance, `nil`, or a sequential collection of segments. A
Shape record matches none of those cases, so `path-data` threw
"unexpected data" every time the user moved the mouse while drawing a
path.

The fix is to call `(st/get-path state :content)` so that only the
`:content` field (a `PathData` instance) is extracted and forwarded to
`path/next-node`.
2026-04-09 09:21:57 +00:00
Marina López
1c68810521 Add can use trial prop in nitrate profile 2026-04-09 11:15:21 +02:00
Aitor Moreno
38a5a67b86
Merge pull request #8912 from penpot/niwinz-main-text-editor-fixes
🐛 Fix TypeError when deleting text at edge spans in text editor
2026-04-09 10:53:07 +02:00
Andrés Moya
deb3af23d4
🐛 Normalize token set names in themes (#8914) 2026-04-09 10:33:56 +02:00
Eva Marco
da6bd7509b
🐛 Fix hot reload on color-row text (#8880) 2026-04-09 10:18:21 +02:00
Eva Marco
c1d815f97c
🐛 Fix go to viewer with frame selected (#8878) 2026-04-09 10:05:56 +02:00
Dream
21217c5622
Add per-group add button for typographies (#8895)
*  Add per-group add button for typographies

Add a "+" button to each typography group header, allowing users to
create new typographies directly inside a group instead of only at
the top level. The button only appears for local, editable files.

Closes #5275

* 📚 Add changelog entry for typography group add button

* 🐛 Fix typography group title button layout wrapping

* ♻️ Address review feedback for typography group add button

Signed-off-by: eureka928 <meobius123@gmail.com>
2026-04-09 09:32:56 +02:00
Alejandro Alonso
f8dd64611f
Merge pull request #8625 from penpot/azazeln28-apply-styles-to-selection
🎉 Feat apply styles to selection
2026-04-09 09:22:24 +02:00
Juanfran
e51e0c7933 Add theme field to nitrate authenticate response 2026-04-09 09:19:36 +02:00
Eva Marco
62b59991a9
🔧 Add guard to apply-token (#8879) 2026-04-09 09:16:28 +02:00
Andrey Antukh
5937a8b0fc Merge remote-tracking branch 'origin/staging' into develop 2026-04-09 09:13:02 +02:00
Andrey Antukh
11fbd4cb21 Merge remote-tracking branch 'origin/main' into staging 2026-04-09 09:12:23 +02:00
Andrey Antukh
dfa45ec8d8 ⬆️ Update deps on root package.json 2026-04-09 09:10:44 +02:00
Alejandro Alonso
27449139ad Merge remote-tracking branch 'origin/staging' into develop 2026-04-09 09:05:02 +02:00
Alejandro Alonso
90fcc9f597
Merge pull request #8903 from penpot/alotor-fix-text-grow-problem
🐛 Fix problem with text auto grow in layouts
2026-04-09 08:26:18 +02:00
Andrey Antukh
5a2c09f246 🐛 Fix TypeError when deleting text at edge spans in text editor
The text editor's SelectionController threw 'TypeError: Invalid text
node' when:

- Pressing Backspace to delete the only character of the **first** text
  span in a paragraph that contains multiple spans.
- Pressing Delete to delete the only character of the **last** text
  span in the same situation.
- Pressing a word-backward shortcut that empties the first span of a
  multi-span paragraph.

In all three cases the tree-iterator (previousNode / nextNode) returned
null because no sibling text node existed in that direction, and that
null was subsequently passed to getTextNodeLength() which calls
isTextNode() — which unconditionally throws when given a falsy value.

Fix: use the null-coalescing fallback to the first/last remaining
child's text node of the paragraph before calling collapse() /
getTextNodeLength().
2026-04-08 21:03:46 +02:00
Alejandro Alonso
8f6133ddac
Merge pull request #8853 from penpot/alotor-performance-tokens
🐛 Fix problem with token performance
2026-04-08 18:15:26 +02:00
andrés gonzález
6063c1c532
📚Clarify remote MCP availability in production (#8910) 2026-04-08 17:48:05 +02:00
Andrey Antukh
ffac8d2861 📎 Update changelog 2.14.2 2026-04-08 17:34:00 +02:00
Andrey Antukh
f97df3e8ab 🐛 Fix PathData corruption root causes across WASM and CLJS
Replace unsafe std::mem::transmute calls in Rust WASM path code with
validated TryFrom conversions to prevent undefined behavior from invalid
enum discriminant values. This was the most likely root cause of the
"No matching clause: -19772" production crash -- corrupted bytes flowing
through transmute could produce arbitrary invalid enum variants.

Fix byteOffset handling throughout the CLJS PathData serialization
pipeline. DataView instances created via buf/slice carry a non-zero
byteOffset, but from-bytes, transit write handler, -write-to,
buf/clone, and buf/equals? all operated on the full underlying
ArrayBuffer, ignoring offset and length. This could silently produce
PathData with incorrect size or content.

Rust changes (render-wasm):
- RawSegmentData: From<[u8; N]> -> TryFrom<[u8; N]> with discriminant
  validation (must be 0x01-0x04) before transmuting
- RawBoolType: From<u8> -> TryFrom<u8> with explicit match on 0-3
- Add #[wasm_error] to set_shape_path_content, current_to_path,
  convert_stroke_to_path, and set_shape_bool_type so panics are caught
  and routed through the WASM error protocol instead of crashing
- set_shape_path_content: replace .expect() with proper Result/? error
  propagation per segment
- Remove unused From<BytesType> bound from SerializableResult trait

CLJS changes (common):
- from-bytes: use DataView.byteLength instead of ArrayBuffer.byteLength
  for DataView inputs; preserve byteOffset/byteLength when converting
  from Uint8Array, Uint32Array, and Int8Array
- Transit write handler: construct Uint8Array with byteOffset and
  byteLength from the DataView, not the full backing ArrayBuffer
- -write-to: same byteOffset/byteLength fix
- buf/clone: copy only the DataView byte range using Uint8Array with
  proper offset, not Uint32Array over the full ArrayBuffer
- buf/equals?: compare DataView byte ranges using Uint8Array with
  proper offset, not the full backing ArrayBuffers

Frontend changes:
- shape-to-path, stroke-to-path, calculate-bool*: wrap WASM call and
  buffer read in try/catch to ensure mem/free is always called, even
  when an exception occurs between the WASM call and the free call

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-04-08 17:24:09 +02:00
Andrey Antukh
b63e4a297b 🐛 Handle corrupted PathData segments gracefully instead of crashing
Add nil defaults to all case expressions that match binary segment
type codes so that corrupted/unknown values are skipped instead of
throwing 'No matching clause'. This prevents a React render crash
(triggered via shape-with-open-path? -> get-subpaths -> reduce)
when a PathData buffer contains invalid bytes, e.g. from a WASM
data transfer or deserialization of damaged stored data.

Affected functions: read-segment, impl-walk, impl-reduce,
impl-lookup, to-string-segment*, and the seq/reduce protocol
implementations on both JVM and CLJS PathData types.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-04-08 17:21:03 +02:00
Andrey Antukh
6a0d131715 🐛 Fix swapped move-to/line-to type codes in PathData binary readers
The impl-walk, impl-reduce, and impl-lookup functions had the binary
type codes for move-to and line-to swapped (1 mapped to :line-to and
2 to :move-to). This is inconsistent with from-plain, read-segment,
to-string-segment*, and the Rust RawSegmentData enum which all use
1=move-to and 2=line-to. The swap caused incorrect command types to
be reported to callers like get-handlers and get-points.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-04-08 17:20:47 +02:00