Merge remote-tracking branch 'origin/staging' into develop

This commit is contained in:
Andrey Antukh 2026-04-22 13:31:58 +02:00
commit 8ad30e14b6
9 changed files with 62 additions and 35 deletions

View File

@ -367,6 +367,9 @@
(when (cf/check-browser? :safari) (when (cf/check-browser? :safari)
(mf/deref refs/selected-zoom)) (mf/deref refs/selected-zoom))
vbox
(mf/deref refs/vbox)
shape (cond-> shape shape (cond-> shape
(some? text-modifier) (some? text-modifier)
(dwt/apply-text-modifier text-modifier) (dwt/apply-text-modifier text-modifier)
@ -385,13 +388,20 @@
selrect-width (:width selrect) selrect-width (:width selrect)
max-width (max width selrect-width) max-width (max width selrect-width)
max-height (max height selrect-height) max-height (max height selrect-height)
;; During auto-width editing we keep the shape width trimmed, but the caret
;; must be able to move after trailing spaces. Expand only the editor
;; overlay up to one viewport width to avoid clipping caret rendering.
viewport-width (or (:width vbox) 0)
overlay-width (if (= (:grow-type shape) :auto-width)
(+ max-width viewport-width)
max-width)
valign (-> shape :content :vertical-align) valign (-> shape :content :vertical-align)
y (:y selrect) y (:y selrect)
y (case valign y (case valign
"bottom" (+ y (- selrect-height height)) "bottom" (+ y (- selrect-height height))
"center" (+ y (/ (- selrect-height height) 2)) "center" (+ y (/ (- selrect-height height) 2))
y)] y)]
[(assoc selrect :y y :width max-width :height max-height) transform]) [(assoc selrect :y y :width overlay-width :height max-height) transform])
(let [bounds (gst/shape->rect shape) (let [bounds (gst/shape->rect shape)
x (mth/min (dm/get-prop bounds :x) x (mth/min (dm/get-prop bounds :x)

View File

@ -48,7 +48,10 @@
font-size: 0; font-size: 0;
} }
[data-itype="inline"] { // Text spans emitted by @penpot/text-editor use `data-itype="span"`.
// Keep whitespace rules attached to the real node type so trailing spaces
// are handled consistently while editing.
[data-itype="span"] {
box-sizing: content-box; box-sizing: content-box;
display: inline; display: inline;
line-height: inherit; line-height: inherit;
@ -68,11 +71,11 @@
.grow-type-auto-width { .grow-type-auto-width {
[data-itype="span"], [data-itype="span"],
[data-itype="paragraph"] { [data-itype="paragraph"] {
white-space: nowrap; // Keep auto-width editing on a single preformatted line so trailing
} // spaces are part of caret geometry and browser selection math.
white-space: pre;
[data-itype="span"] { overflow-wrap: normal;
white-space-collapse: preserve; word-break: keep-all;
} }
} }

View File

@ -157,6 +157,10 @@
text-editor-ref (mf/use-ref nil) text-editor-ref (mf/use-ref nil)
last-vern-ref (mf/use-ref nil) last-vern-ref (mf/use-ref nil)
;; WASM grid overlay was visible last run (`hover-grid?` true). Used so `clear-grid`
;; (expensive: `_hide_grid` + full `request-render`) runs only when hiding the overlay.
prev-hover-grid-shown?-ref (mf/use-ref false)
;; STATE REFS ;; STATE REFS
disable-paste-ref (mf/use-ref false) disable-paste-ref (mf/use-ref false)
in-viewport-ref (mf/use-ref false) in-viewport-ref (mf/use-ref false)
@ -253,9 +257,10 @@
(not page-transition?)) (not page-transition?))
show-text-editor? (and editing-shape (= :text (:type editing-shape)) (not page-transition?)) show-text-editor? (and editing-shape (= :text (:type editing-shape)) (not page-transition?))
hover-grid? (and (some? @hover-top-frame-id) has-grid? (and (some? @hover-top-frame-id)
(ctl/grid-layout? objects @hover-top-frame-id) (ctl/grid-layout? objects @hover-top-frame-id))
(not page-transition?))
hover-grid? (and has-grid? (not page-transition?))
show-grid-editor? (and editing-shape (ctl/grid-layout? editing-shape) (not page-transition?)) show-grid-editor? (and editing-shape (ctl/grid-layout? editing-shape) (not page-transition?))
show-presence? (and page-id (not page-transition?)) show-presence? (and page-id (not page-transition?))
@ -427,11 +432,19 @@
(when (and @canvas-init? @initialized?) (when (and @canvas-init? @initialized?)
(wasm.api/set-canvas-background background))) (wasm.api/set-canvas-background background)))
(mf/with-effect [@canvas-init? hover-grid? @hover-top-frame-id] ;; Grid overlay: `clear-grid` must run only when the overlay was shown and is now off
;; (e.g. leave grid frame, or `page-transition?`). Do not call it on every
;; `hover-top-frame-id` change while not hovering a grid frame.
(mf/with-effect [@canvas-init? hover-grid?]
(when @canvas-init? (when @canvas-init?
(if hover-grid? (when (and (not hover-grid?) (mf/ref-val prev-hover-grid-shown?-ref))
(wasm.api/show-grid @hover-top-frame-id) (wasm.api/clear-grid))
(wasm.api/clear-grid)))) (mf/set-ref-val! prev-hover-grid-shown?-ref hover-grid?)))
(mf/with-effect [@canvas-init? has-grid? hover-grid?
(if (and has-grid? hover-grid?) @hover-top-frame-id ::no-grid-hover-id)]
(when (and @canvas-init? hover-grid?)
(wasm.api/show-grid @hover-top-frame-id)))
(hooks/setup-dom-events zoom disable-paste-ref in-viewport-ref read-only? drawing-tool path-drawing?) (hooks/setup-dom-events zoom disable-paste-ref in-viewport-ref read-only? drawing-tool path-drawing?)
(hooks/setup-viewport-size vport viewport-ref) (hooks/setup-viewport-size vport viewport-ref)

View File

@ -334,7 +334,7 @@
(defn request-render (defn request-render
[_requester] [_requester]
(when (and wasm/context-initialized? (not @wasm/context-lost?)) (when (and wasm/context-initialized? (not @wasm/context-lost?) (not @wasm/disable-request-render?))
(if @shapes-loading? (if @shapes-loading?
(register-deferred-render!) (register-deferred-render!)
(when-not @pending-render (when-not @pending-render
@ -1699,6 +1699,8 @@
[] []
(when wasm/context-initialized? (when wasm/context-initialized?
(try (try
(set! wasm/context-initialized? false)
;; Cancel any pending animation frame to prevent race conditions ;; Cancel any pending animation frame to prevent race conditions
(when wasm/internal-frame-id (when wasm/internal-frame-id
(js/cancelAnimationFrame wasm/internal-frame-id) (js/cancelAnimationFrame wasm/internal-frame-id)
@ -1709,8 +1711,6 @@
(reset! shapes-loading? false) (reset! shapes-loading? false)
(reset! deferred-render? false) (reset! deferred-render? false)
;; TODO: perform corresponding cleaning
(set! wasm/context-initialized? false)
(h/call wasm/internal-module "_clean_up") (h/call wasm/internal-module "_clean_up")
;; Remove event listener for WebGL context lost ;; Remove event listener for WebGL context lost

View File

@ -26,6 +26,9 @@
(defonce context-initialized? false) (defonce context-initialized? false)
(defonce context-lost? (atom false)) (defonce context-lost? (atom false))
;; When we're rendering in a sync way we want to stop the asynchrous `request-render`
(defonce disable-request-render? (atom false))
(defonce serializers (defonce serializers
#js {:blur-type shared/RawBlurType #js {:blur-type shared/RawBlurType

View File

@ -170,6 +170,7 @@
(render/calculate-dimensions objects thumbnail-aspect-ratio)) (render/calculate-dimensions objects thumbnail-aspect-ratio))
zoom (/ width (:width vbox))] zoom (/ width (:width vbox))]
(reset! wasm/disable-request-render? true)
(wasm.api/initialize-viewport (wasm.api/initialize-viewport
objects zoom vbox objects zoom vbox
:background bgcolor :background bgcolor

View File

@ -1,6 +1,6 @@
{ {
"name": "@penpot/mcp", "name": "@penpot/mcp",
"version": "2.15.0-rc.1.153", "version": "2.16.0-rc.1.206",
"description": "MCP server for Penpot integration", "description": "MCP server for Penpot integration",
"bin": { "bin": {
"penpot-mcp": "./bin/mcp-local.js" "penpot-mcp": "./bin/mcp-local.js"

0
mcp/scripts/set-version Normal file → Executable file
View File

View File

@ -551,30 +551,27 @@ fn child_position(
child_axis: &ChildAxis, child_axis: &ChildAxis,
track: &TrackData, track: &TrackData,
) -> Point { ) -> Point {
let mid_point = (track.across_size - child_axis.across_size + child_axis.margin_across_start
- child_axis.margin_across_end)
/ 2.0;
let end_point = track.across_size - child_axis.across_size - child_axis.margin_across_end;
let across_position = match child.layout_item { let across_position = match child.layout_item {
Some(LayoutItem { Some(LayoutItem {
align_self: Some(align_self), align_self: Some(align_self),
.. ..
}) => match align_self { }) => match align_self {
AlignSelf::Center => { AlignSelf::Center => mid_point,
(track.across_size - child_axis.across_size + child_axis.margin_across_start AlignSelf::End => end_point,
- child_axis.margin_across_end) _ => match layout_data.align_items {
/ 2.0 AlignItems::Center => mid_point,
} AlignItems::End => end_point,
AlignSelf::End => { _ => child_axis.margin_across_start,
track.across_size - child_axis.across_size - child_axis.margin_across_end },
}
_ => child_axis.margin_across_start,
}, },
_ => match layout_data.align_items { _ => match layout_data.align_items {
AlignItems::Center => { AlignItems::Center => mid_point,
(track.across_size - child_axis.across_size + child_axis.margin_across_start AlignItems::End => end_point,
- child_axis.margin_across_end)
/ 2.0
}
AlignItems::End => {
track.across_size - child_axis.across_size - child_axis.margin_across_end
}
_ => child_axis.margin_across_start, _ => child_axis.margin_across_start,
}, },
}; };