Merge remote-tracking branch 'refs/remotes/origin/develop' into develop

This commit is contained in:
Andrey Antukh 2026-07-27 10:48:54 +02:00
commit 44c15480f2
14 changed files with 60 additions and 45 deletions

View File

@ -11,6 +11,7 @@
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.main.data.helpers :as dsh] [app.main.data.helpers :as dsh]
[app.main.data.workspace.viewport-wasm :as dwvw] [app.main.data.workspace.viewport-wasm :as dwvw]
[app.main.streams :as ms]
[potok.v2.core :as ptk])) [potok.v2.core :as ptk]))
(defn hover-grid-cell (defn hover-grid-cell
@ -88,7 +89,11 @@
(ptk/reify ::stop-grid-layout-editing (ptk/reify ::stop-grid-layout-editing
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(update state :workspace-grid-edition dissoc grid-id)))) (update state :workspace-grid-edition dissoc grid-id))
ptk/EffectEvent
(effect [_ _ _]
(ms/clear-transform-preview!))))
(defn locate-board (defn locate-board
[grid-id] [grid-id]

View File

@ -143,8 +143,7 @@
ptk/EffectEvent ptk/EffectEvent
(effect [_ _ _] (effect [_ _ _]
(rx/push! ms/wasm-modifiers nil) (ms/clear-transform-preview!))))
(rx/push! ms/workspace-selrect nil))))
;; -- Resize -------------------------------------------------------- ;; -- Resize --------------------------------------------------------

View File

@ -32,6 +32,17 @@
(defonce workspace-selrect (defonce workspace-selrect
(rx/behavior-subject nil)) (rx/behavior-subject nil))
(defn clear-transform-preview!
"Reset the interactive-transform preview behaviour-subjects. Controls
that drive a live preview (drag/resize/rotate, flex spacing handles,
grid track/cell gestures) set these via `set-wasm-modifiers` and clear
them at gesture end. If the control unmounts mid-gesture that clearing
never runs, so the stale selrect keeps displacing the DOM selection
overlay of the next selection. Call from gesture end / unmount cleanup."
[]
(rx/push! wasm-modifiers nil)
(rx/push! workspace-selrect nil))
;; --- Derived streams ;; --- Derived streams
(defonce ^:private pointer (defonce ^:private pointer

View File

@ -357,9 +357,11 @@
(tr "dashboard.my-teams")] (tr "dashboard.my-teams")]
(when (= default-team-id (:default-team-id organization)) (when (= default-team-id (:default-team-id organization))
tick-icon)] tick-icon)]
[:hr {:role "separator" :class (stl/css :team-separator)}] (when (seq organizations)
[:li {:role "presentation" :class (stl/css :org-section-label)} [:*
(tr "dashboard.section.organizations")] [:hr {:role "separator" :class (stl/css :team-separator)}]
[:li {:role "presentation" :class (stl/css :org-section-label)}
(tr "dashboard.section.organizations")]])
(for [org-item organizations] (for [org-item organizations]
[:> dropdown-menu-item* {:on-click on-org-click [:> dropdown-menu-item* {:on-click on-org-click

View File

@ -1,9 +1,19 @@
(ns app.main.ui.flex-controls.common (ns app.main.ui.flex-controls.common
(:require (:require
[app.main.constants :as mconst] [app.main.constants :as mconst]
[app.main.streams :as ms]
[app.main.ui.formats :as fmt] [app.main.ui.formats :as fmt]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
;; ------------------------------------------------
;; INTERACTIVE TRANSFORM CLEANUP
;; ------------------------------------------------
;; Flex spacing controls (padding/margin/gap) call this from their
;; unmount cleanup, guarded on the resizing flag. See
;; `ms/clear-transform-preview!` for the rationale.
(def clear-transform-preview! ms/clear-transform-preview!)
;; ------------------------------------------------ ;; ------------------------------------------------
;; CONSTANTS ;; CONSTANTS
;; ------------------------------------------------ ;; ------------------------------------------------

View File

@ -98,6 +98,11 @@
(when on-change (when on-change
(on-change modifiers)))))))] (on-change modifiers)))))))]
(mf/with-effect []
(fn []
(when (some? @resizing)
(fcc/clear-transform-preview!))))
[:g.gap-rect [:g.gap-rect
[:rect.info-area [:rect.info-area
{:x (:x rect-data) {:x (:x rect-data)

View File

@ -105,6 +105,11 @@
(when on-change (when on-change
(on-change modifiers)))))))] (on-change modifiers)))))))]
(mf/with-effect []
(fn []
(when @resizing?
(fcc/clear-transform-preview!))))
[:rect.margin-rect [:rect.margin-rect
{:x (:x rect-data) {:x (:x rect-data)
:y (:y rect-data) :y (:y rect-data)

View File

@ -105,6 +105,11 @@
(when on-change (when on-change
(on-change modifiers)))))))] (on-change modifiers)))))))]
(mf/with-effect []
(fn []
(when @resizing?
(fcc/clear-transform-preview!))))
[:g.padding-rect [:g.padding-rect
[:rect.info-area [:rect.info-area
{:x (:x rect-data) {:x (:x rect-data)

View File

@ -12,8 +12,8 @@
"clean": "rm -rf dist/" "clean": "rm -rf dist/"
}, },
"dependencies": { "dependencies": {
"@penpot/plugin-styles": "1.4.2", "@penpot/plugin-styles": "1.5.0",
"@penpot/plugin-types": "1.4.2" "@penpot/plugin-types": "1.5.0"
}, },
"devDependencies": { "devDependencies": {
"cross-env": "^10.1.0", "cross-env": "^10.1.0",

View File

@ -214,8 +214,6 @@ export class PenpotUtils {
public static getBounds(shape: Shape): Bounds { public static getBounds(shape: Shape): Bounds {
if (shape.type === "text") { if (shape.type === "text") {
const text = shape as Text; const text = shape as Text;
// TODO: Remove ts-ignore once type definitions are updated
// @ts-ignore
return text.textBounds; return text.textBounds;
} else { } else {
return shape.bounds; return shape.bounds;
@ -473,7 +471,6 @@ export class PenpotUtils {
*/ */
public static findTokensByName(name: string): any[] { public static findTokensByName(name: string): any[] {
const tokens: any[] = []; const tokens: any[] = [];
// @ts-ignore
const tokenCatalog = penpot.library.local.tokens; const tokenCatalog = penpot.library.local.tokens;
for (const set of tokenCatalog.sets) { for (const set of tokenCatalog.sets) {
@ -494,7 +491,6 @@ export class PenpotUtils {
* @returns The first matching token, or null if not found * @returns The first matching token, or null if not found
*/ */
public static findTokenByName(name: string): any | null { public static findTokenByName(name: string): any | null {
// @ts-ignore
const tokenCatalog = penpot.library.local.tokens; const tokenCatalog = penpot.library.local.tokens;
for (const set of tokenCatalog.sets) { for (const set of tokenCatalog.sets) {
@ -515,7 +511,6 @@ export class PenpotUtils {
* @returns The TokenSet containing this token, or null if not found * @returns The TokenSet containing this token, or null if not found
*/ */
public static getTokenSet(token: any): any | null { public static getTokenSet(token: any): any | null {
// @ts-ignore
const tokenCatalog = penpot.library.local.tokens; const tokenCatalog = penpot.library.local.tokens;
for (const set of tokenCatalog.sets) { for (const set of tokenCatalog.sets) {
@ -571,7 +566,6 @@ export class PenpotUtils {
} }
// 1. Create the variant container // 1. Create the variant container
// @ts-ignore — createVariantFromComponents was added after plugin-types@1.4.1
const container: VariantContainer = (penpot as any).createVariantFromComponents(components.map((c) => c.shape)); const container: VariantContainer = (penpot as any).createVariantFromComponents(components.map((c) => c.shape));
const variants = container.variants; const variants = container.variants;
if (!variants) { if (!variants) {
@ -617,7 +611,6 @@ export class PenpotUtils {
*/ */
public static tokenOverview(): Record<string, Record<string, string[]>> { public static tokenOverview(): Record<string, Record<string, string[]>> {
const overview: Record<string, Record<string, string[]>> = {}; const overview: Record<string, Record<string, string[]>> = {};
// @ts-ignore
const tokenCatalog = penpot.library.local.tokens; const tokenCatalog = penpot.library.local.tokens;
for (const set of tokenCatalog.sets) { for (const set of tokenCatalog.sets) {

View File

@ -38,8 +38,6 @@ export class Task<TParams = any> {
// Send to main.ts which will forward to MCP server via WebSocket // Send to main.ts which will forward to MCP server via WebSocket
try { try {
// TODO: Remove ts-ignore once Penpot types have been updated
// @ts-ignore
penpot.ui.sendMessage(response, true); penpot.ui.sendMessage(response, true);
} catch (sendError) { } catch (sendError) {
console.error("Failed to transfer task response for transmission to MCP server", sendError); console.error("Failed to transfer task response for transmission to MCP server", sendError);

View File

@ -1,12 +1,3 @@
import "@penpot/plugin-types";
declare module "@penpot/plugin-types" {
interface Penpot {
/** The Penpot application version string. */
version: string;
}
}
interface McpOptions { interface McpOptions {
getToken(): string; getToken(): string;
getServerUrl(): string; getServerUrl(): string;

View File

@ -196,20 +196,13 @@ export class ExecuteCodeTaskHandler extends TaskHandler<ExecuteCodeTaskParams> {
const code = task.params.code; const code = task.params.code;
// set the flags naturalChildOrdering and throwValidationErrors to true during code execution. // set the flags naturalChildOrdering and throwValidationErrors to true during code execution.
// TODO: Remove all ts-ignore once Penpot types have been updated
let originalNaturalChildOrdering: any, originalThrowValidationErrors: any; let originalNaturalChildOrdering: any, originalThrowValidationErrors: any;
// @ts-ignore
if (penpot.flags) { if (penpot.flags) {
// @ts-ignore
originalNaturalChildOrdering = penpot.flags.naturalChildOrdering; originalNaturalChildOrdering = penpot.flags.naturalChildOrdering;
// @ts-ignore
penpot.flags.naturalChildOrdering = true; penpot.flags.naturalChildOrdering = true;
// @ts-ignore
originalThrowValidationErrors = penpot.flags.throwValidationErrors; originalThrowValidationErrors = penpot.flags.throwValidationErrors;
// @ts-ignore
penpot.flags.throwValidationErrors = true; penpot.flags.throwValidationErrors = true;
} else { } else {
// TODO: This can be removed once `flags` has been merged to PROD
throw new Error( throw new Error(
"You are using a version of the Penpot MCP server which is incompatible " + "You are using a version of the Penpot MCP server which is incompatible " +
"with the connected Penpot version. " + "with the connected Penpot version. " +
@ -228,9 +221,7 @@ export class ExecuteCodeTaskHandler extends TaskHandler<ExecuteCodeTaskParams> {
})(context); })(context);
} finally { } finally {
// restore the original value of the flags // restore the original value of the flags
// @ts-ignore
penpot.flags.naturalChildOrdering = originalNaturalChildOrdering; penpot.flags.naturalChildOrdering = originalNaturalChildOrdering;
// @ts-ignore
penpot.flags.throwValidationErrors = originalThrowValidationErrors; penpot.flags.throwValidationErrors = originalThrowValidationErrors;
} }

20
mcp/pnpm-lock.yaml generated
View File

@ -24,11 +24,11 @@ importers:
packages/plugin: packages/plugin:
dependencies: dependencies:
'@penpot/plugin-styles': '@penpot/plugin-styles':
specifier: 1.4.2 specifier: 1.5.0
version: 1.4.2 version: 1.5.0
'@penpot/plugin-types': '@penpot/plugin-types':
specifier: 1.4.2 specifier: 1.5.0
version: 1.4.2 version: 1.5.0
devDependencies: devDependencies:
cross-env: cross-env:
specifier: ^10.1.0 specifier: ^10.1.0
@ -496,11 +496,11 @@ packages:
'@oxc-project/types@0.137.0': '@oxc-project/types@0.137.0':
resolution: {integrity: sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==} resolution: {integrity: sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==}
'@penpot/plugin-styles@1.4.2': '@penpot/plugin-styles@1.5.0':
resolution: {integrity: sha512-/Rn6xy80W+mxAi6j5/SOiNY8P0qHMB1WW+j+nyZajecFSnVGPzSWOiMcIDH+Jtsz7Xpmd5AICpgVM0xjechQig==} resolution: {integrity: sha512-rwXFBRPd0IZs3ens+eRT8oA5WqkQgF6xlW6fCfH7U1NHRjej9HH7vTGXmfjoIVml6Xx1sbyYHZVxkQC8Ub8+zA==}
'@penpot/plugin-types@1.4.2': '@penpot/plugin-types@1.5.0':
resolution: {integrity: sha512-O8wU6RSYE8bIVU7g8cSTYi32ppxs3R13dq7X3Nn9tmDaJjBOKOBpVLuoRPIp3fJC65fv8/7om0sdrtFoL5v19g==} resolution: {integrity: sha512-hFk4Rx66rLaSUWoN6bhxXkDI2ymwKg9xokdslvZvXM5MSmEmfhsJKUMwtuzgYWljbbfaQhK+DjK8g8yVbbavtA==}
'@pinojs/redact@0.4.0': '@pinojs/redact@0.4.0':
resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==}
@ -1762,9 +1762,9 @@ snapshots:
'@oxc-project/types@0.137.0': {} '@oxc-project/types@0.137.0': {}
'@penpot/plugin-styles@1.4.2': {} '@penpot/plugin-styles@1.5.0': {}
'@penpot/plugin-types@1.4.2': {} '@penpot/plugin-types@1.5.0': {}
'@pinojs/redact@0.4.0': {} '@pinojs/redact@0.4.0': {}