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

This commit is contained in:
Andrey Antukh 2026-04-21 22:38:45 +02:00
commit c259fbdb5b
27 changed files with 206 additions and 174 deletions

View File

@ -1,6 +1,6 @@
# CHANGELOG
## 2.16.0 (Unreleased)
## 2.17.0 (Unreleased)
### :boom: Breaking changes & Deprecations
@ -72,7 +72,8 @@
- Fix copy to be more specific [Taiga #13990](https://tree.taiga.io/project/penpot/issue/13990)
- Allow deleting the profile avatar after uploading [Github #9067](https://github.com/penpot/penpot/issues/9067)
## 2.15.0 (Unreleased)
## 2.16.0 (Unreleased)
### :boom: Breaking changes & Deprecations
@ -96,6 +97,19 @@
- Fix text editor v1 focus [Taiga #13961](https://tree.taiga.io/project/penpot/issue/13961)
## 2.15.0 (Unreleased)
### :sparkles: New features & Enhancements
- Add MCP server integration [Taiga #13112](https://tree.taiga.io/project/penpot/us/13112)
- Add chunked upload API for large media and binary files (removes previous upload size limits) [Github #8909](https://github.com/penpot/penpot/pull/8909)
### :bug: Bugs fixed
- Fix incorrect handling of version restore operation [Github #9041](https://github.com/penpot/penpot/pull/9041)
- Fix removeChild errors from unmount race conditions [Github #8927](https://github.com/penpot/penpot/pull/8927)
## 2.14.3
### :sparkles: New features & Enhancements
@ -186,6 +200,8 @@
- Optimize sidebar performance for deeply nested shapes [Taiga #13017](https://tree.taiga.io/project/penpot/task/13017)
- Remove tokens path node and bulk remove tokens [Taiga #13007](https://tree.taiga.io/project/penpot/us/13007)
- Replace themes management modal radio buttons for switches [Taiga #9215](https://tree.taiga.io/project/penpot/us/9215)
- [MCP server] Integrations section [Taiga #13112](https://tree.taiga.io/project/penpot/us/13112)
- [Access Tokens] Look & feel refinement [Taiga #13114](https://tree.taiga.io/project/penpot/us/13114)
### :bug: Bugs fixed

View File

@ -380,7 +380,6 @@
(rx/take 1)
(rx/tap (fn [_] (perf/setup)))))
(->> stream
(rx/filter (ptk/type? ::dps/persistence-notification))
(rx/take 1)
@ -488,8 +487,8 @@
:selected-before selected-before}]
(rx/of (dwu/append-undo entry stack-undo?)))
(rx/empty))))))
(rx/take-until stoper-s))
(rx/take-until stoper-s))
(rx/of (mcp/notify-other-tabs-disconnect)))))
ptk/EffectEvent

View File

@ -545,7 +545,6 @@
(ex/print-throwable cause :prefix "Uncaught Rejection")
(ts/asap #(flash :cause cause :type :unhandled))))))))]
(.addEventListener g/window "error" on-unhandled-error)
(.addEventListener g/window "unhandledrejection" on-unhandled-rejection)
(fn []

View File

@ -24,7 +24,7 @@
[app.main.ui.workspace.color-palette :refer [color-palette*]]
[app.main.ui.workspace.color-palette-ctx-menu :refer [color-palette-ctx-menu*]]
[app.main.ui.workspace.text-palette :refer [text-palette*]]
[app.main.ui.workspace.text-palette-ctx-menu :refer [text-palette-ctx-menu]]
[app.main.ui.workspace.text-palette-ctx-menu :refer [text-palette-ctx-menu*]]
[app.util.dom :as dom]
[app.util.i18n :refer [tr]]
[app.util.object :as obj]
@ -203,10 +203,10 @@
:ref container}
(when text-palette?
[:*
[:& text-palette-ctx-menu {:show-menu? show-menu?
:close-menu on-close-menu
:on-select-palette on-select-text-palette-menu
:selected selected-text}]
[:> text-palette-ctx-menu* {:show-menu show-menu?
:close-menu on-close-menu
:on-select-palette on-select-text-palette-menu
:selected selected-text}]
[:> text-palette* {:size size
:selected selected-text
:width vport-width}]])

View File

@ -16,7 +16,7 @@
[app.render-wasm.api :as wasm.api]
[rumext.v2 :as mf]))
(mf/defc text-edition-outline
(mf/defc text-edition-outline*
[{:keys [shape zoom modifiers]}]
(if (features/active-feature? @st/state "render-wasm/v1")
(let [selrect-transform (mf/deref refs/workspace-selrect)

View File

@ -258,7 +258,7 @@
(map (resolve-shape-types entries objects))
(mapv select-entry)))
(mf/defc history-entry-details [{:keys [entry]}]
(mf/defc history-entry-details* [{:keys [entry]}]
(let [{entries :items} (mf/deref workspace-undo)
objects (mf/deref refs/workspace-page-objects)]
@ -319,7 +319,7 @@
deprecated-icon/arrow])]
(when @show-detail?
[:& history-entry-details {:entry entry}])]))
[:> history-entry-details* {:entry entry}])]))
(mf/defc history-toolbox*
[]

View File

@ -32,7 +32,7 @@
:value 4
:hidden false}))
(mf/defc blur-menu [{:keys [ids type values]}]
(mf/defc blur-menu* [{:keys [ids type values]}]
(let [blur (:blur values)
has-value? (not (nil? blur))
render-wasm? (features/use-feature "render-wasm/v1")

View File

@ -28,7 +28,7 @@
:parent-id
:frame-id])
(mf/defc constraints-menu
(mf/defc constraints-menu*
[{:keys [ids values] :as props}]
(let [state* (mf/use-state true)
open? (deref state*)

View File

@ -33,7 +33,7 @@
:separator
18 12 10 8 6 4 3 2])
(mf/defc grid-options
(mf/defc grid-options*
{::mf/wrap [mf/memo]}
[{:keys [shape-id index grid frame-width frame-height default-grid-params]}]
(let [on-change (mf/use-fn (mf/deps shape-id index) #(st/emit! (dw/set-frame-grid shape-id index %)))
@ -296,7 +296,7 @@
[:button {:class (stl/css :option-btn)
:on-click handle-set-as-default} (tr "workspace.options.grid.params.set-default")]])]])])]))
(mf/defc frame-grid
(mf/defc frame-grid*
[{:keys [shape]}]
(let [state* (mf/use-state true)
open? (deref state*)
@ -331,12 +331,12 @@
(when (and open? (seq frame-grids))
[:div {:class (stl/css :element-set-content)}
(for [[index grid] (map-indexed vector frame-grids)]
[:& grid-options {:key (str id "-" index)
:shape-id id
:grid grid
:index index
:frame-width (:width shape)
:frame-height (:height shape)
:default-grid-params default-grid-params}])])]))
[:> grid-options* {:key (str id "-" index)
:shape-id id
:grid grid
:index index
:frame-width (:width shape)
:frame-height (:height shape)
:default-grid-params default-grid-params}])])]))

View File

@ -38,7 +38,7 @@
:stroke-cap-start
:stroke-cap-end])
(mf/defc stroke-menu
(mf/defc stroke-menu*
{::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values" "type" "show-caps" "applied-tokens"]))]}
[{:keys [ids type values show-caps disable-stroke-style applied-tokens shapes objects] :as props}]
(let [label (case type

View File

@ -17,7 +17,8 @@
[app.util.i18n :refer [tr]]
[rumext.v2 :as mf]))
(mf/defc attribute-value [{:keys [attr value on-change on-delete] :as props}]
(mf/defc attribute-value*
[{:keys [attr value on-change on-delete]}]
(let [last-value (mf/use-state value)
handle-change*
@ -56,13 +57,14 @@
(str (d/name (last attr)))]
(for [[key value] value]
[:div {:class (stl/css :attr-row) :key key}
[:& attribute-value {:key key
:attr (conj attr key)
:value value
:on-change on-change
:on-delete on-delete}]])])]))
[:> attribute-value* {:key key
:attr (conj attr key)
:value value
:on-change on-change
:on-delete on-delete}]])])]))
(mf/defc svg-attrs-menu [{:keys [ids values]}]
(mf/defc svg-attrs-menu*
[{:keys [ids values]}]
(let [state* (mf/use-state true)
open? (deref state*)
attrs (:svg-attrs values)
@ -103,8 +105,8 @@
(when open?
[:div {:class (stl/css :element-set-content)}
(for [[attr-key attr-value] attrs]
[:& attribute-value {:key attr-key
:attr [attr-key]
:value attr-value
:on-change handle-change
:on-delete handle-delete}])])])))
[:> attribute-value* {:key attr-key
:attr [attr-key]
:value attr-value
:on-change handle-change
:on-delete handle-delete}])])])))

View File

@ -79,7 +79,6 @@
(mf/defc text-direction-options*
[{:keys [values on-change on-blur]}]
(let [direction (:text-direction values)
handle-change
(mf/use-fn
(mf/deps on-change on-blur direction)
@ -103,7 +102,6 @@
(mf/defc vertical-align*
[{:keys [values on-change on-blur]}]
(let [vertical-align (or (:vertical-align values) "top")
handle-change
(mf/use-fn
(mf/deps on-change on-blur)
@ -135,11 +133,26 @@
handle-change
(mf/use-fn
(mf/deps ids on-blur on-change editor-instance)
(mf/deps ids on-blur editor-instance)
(fn [value]
(on-change {:grow-type (keyword value)})
(when (some? on-blur)
(on-blur))))]
(on-blur)
(let [uid (js/Symbol)
grow-type (keyword value)]
(st/emit! (dwu/start-undo-transaction uid))
(when (features/active-feature? @st/state "text-editor/v2")
(let [content (when editor-instance
(content/dom->cljs (dwt/get-editor-root editor-instance)))]
(when (some? content)
(st/emit! (dwt/v2-update-text-shape-content (first ids) content :finalize? true)))))
(st/emit! (dwsh/update-shapes ids #(assoc % :grow-type grow-type)))
(when (features/active-feature? @st/state "render-wasm/v1")
(st/emit! (dwwt/resize-wasm-text-all ids)
(ptk/data-event :layout/update {:ids ids})))
;; We asynchronously commit so every sychronous event is resolved first and inside the transaction
(ts/schedule #(st/emit! (dwu/commit-undo-transaction uid))))
(when (some? on-blur) (on-blur))))]
[:div {:class (stl/css :grow-options)}
[:> radio-buttons* {:selected (d/name grow-type)
@ -410,9 +423,9 @@
(dom/focus! (txu/get-text-editor-content)))))))
common-props
(mf/spread-props {} {:values values
:on-change on-change
:on-blur on-text-blur})]
(mf/props {:values values
:on-change on-change
:on-blur on-text-blur})]
(hooks/use-stream
expand-stream

View File

@ -9,8 +9,8 @@
[app.common.data.macros :as dm]
[app.common.types.shape.layout :as ctl]
[app.main.refs :as refs]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu*]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu*]]
[app.main.ui.workspace.sidebar.options.menus.exports :refer [exports-menu* exports-attrs]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill]
[app.main.ui.workspace.sidebar.options.menus.grid-cell :as grid-cell]
@ -19,7 +19,7 @@
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu*]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu*]]
[rumext.v2 :as mf]))
(mf/defc options*
@ -118,8 +118,8 @@
:shape shape}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
[:& constraints-menu {:ids ids
:values constraint-values}])
[:> constraints-menu* {:ids ids
:values constraint-values}])
[:> fill/fill-menu*
{:ids ids
@ -127,15 +127,15 @@
:values shape
:applied-tokens applied-tokens}]
[:& stroke-menu {:ids ids
:type type
:show-caps true
:values stroke-values
:applied-tokens applied-tokens}]
[:> stroke-menu* {:ids ids
:type type
:show-caps true
:values stroke-values
:applied-tokens applied-tokens}]
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
[:& blur-menu {:ids ids
:values (select-keys shape [:blur])}]
[:> blur-menu* {:ids ids
:values (select-keys shape [:blur])}]
[:> exports-menu* {:type type
:ids ids

View File

@ -9,8 +9,8 @@
[app.common.data.macros :as dm]
[app.common.types.shape.layout :as ctl]
[app.main.refs :as refs]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu*]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu*]]
[app.main.ui.workspace.sidebar.options.menus.exports :refer [exports-menu* exports-attrs]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill]
[app.main.ui.workspace.sidebar.options.menus.grid-cell :as grid-cell]
@ -19,8 +19,8 @@
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu*]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu*]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu*]]
[rumext.v2 :as mf]))
(mf/defc options*
@ -117,8 +117,8 @@
:shape shape}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
[:& constraints-menu {:ids ids
:values constraint-values}])
[:> constraints-menu* {:ids ids
:values constraint-values}])
[:> fill/fill-menu*
{:ids ids
@ -126,15 +126,15 @@
:values shape
:applied-tokens applied-tokens}]
[:& stroke-menu {:ids ids
:type type
:values stroke-values
:applied-tokens applied-tokens}]
[:> stroke-menu* {:ids ids
:type type
:values stroke-values
:applied-tokens applied-tokens}]
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
[:& blur-menu {:ids ids
:values (select-keys shape [:blur])}]
[:& svg-attrs-menu {:ids ids
:values (select-keys shape [:svg-attrs])}]
[:> blur-menu* {:ids ids
:values (select-keys shape [:blur])}]
[:> svg-attrs-menu* {:ids ids
:values (select-keys shape [:svg-attrs])}]
[:> exports-menu* {:type type
:ids ids
:shapes shapes

View File

@ -10,20 +10,20 @@
[app.common.types.component :as ctk]
[app.common.types.shape.layout :as ctl]
[app.main.refs :as refs]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu*]]
[app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu*]]
[app.main.ui.workspace.sidebar.options.menus.component :refer [component-menu* component-variant-main*]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu*]]
[app.main.ui.workspace.sidebar.options.menus.exports :refer [exports-menu* exports-attrs]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill]
[app.main.ui.workspace.sidebar.options.menus.frame-grid :refer [frame-grid]]
[app.main.ui.workspace.sidebar.options.menus.frame-grid :refer [frame-grid*]]
[app.main.ui.workspace.sidebar.options.menus.grid-cell :as grid-cell]
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu*]]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-flex-attrs layout-container-menu]]
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [select-measure-keys measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu*]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu*]]
[rumext.v2 :as mf]))
(mf/defc options*
@ -140,8 +140,8 @@
:shape shape}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
[:& constraints-menu {:ids ids
:values constraint-values}])
[:> constraints-menu* {:ids ids
:values constraint-values}])
[:> fill/fill-menu*
{:ids ids
@ -149,18 +149,18 @@
:values shape
:applied-tokens applied-tokens}]
[:& stroke-menu {:ids ids
:type shape-type
:values stroke-values
:applied-tokens applied-tokens}]
[:> stroke-menu* {:ids ids
:type shape-type
:values stroke-values
:applied-tokens applied-tokens}]
[:> color-selection-menu* {:type shape-type
:shapes shapes-with-children
:file-id file-id
:libraries libraries}]
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
[:& blur-menu {:ids ids
:values (select-keys shape [:blur])}]
[:& frame-grid {:shape shape}]
[:> blur-menu* {:ids ids
:values (select-keys shape [:blur])}]
[:> frame-grid* {:shape shape}]
[:> exports-menu* {:type shape-type
:ids ids
:shapes shapes

View File

@ -11,9 +11,9 @@
[app.common.data.macros :as dm]
[app.common.types.shape.layout :as ctl]
[app.main.refs :as refs]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu*]]
[app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu*]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraints-menu*]]
[app.main.ui.workspace.sidebar.options.menus.exports :refer [exports-menu* exports-attrs]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill]
[app.main.ui.workspace.sidebar.options.menus.grid-cell :as grid-cell]
@ -22,8 +22,8 @@
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu*]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-menu*]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu*]]
[app.main.ui.workspace.sidebar.options.menus.text :as ot]
[app.main.ui.workspace.sidebar.options.shapes.multiple :refer [get-attrs]]
[rumext.v2 :as mf]))
@ -143,7 +143,7 @@
:values layout-item-values}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
[:& constraints-menu {:ids constraint-ids :values constraint-values}])
[:> constraints-menu* {:ids constraint-ids :values constraint-values}])
(when-not (empty? fill-ids)
[:> fill/fill-menu*
@ -153,10 +153,10 @@
:applied-tokens fill-tokens}])
(when-not (empty? stroke-ids)
[:& stroke-menu {:type type
:ids stroke-ids
:values stroke-values
:applied-tokens stroke-tokens}])
[:> stroke-menu* {:type type
:ids stroke-ids
:values stroke-values
:applied-tokens stroke-tokens}])
[:> color-selection-menu*
{:type type
@ -168,7 +168,7 @@
[:> shadow-menu* {:ids ids :values (get shape :shadow) :type type}])
(when-not (empty? blur-ids)
[:& blur-menu {:type type :ids blur-ids :values blur-values}])
[:> blur-menu* {:type type :ids blur-ids :values blur-values}])
(when-not (empty? text-ids)
[:> ot/text-menu* {:type type
@ -177,7 +177,7 @@
:applied-tokens text-tokens}])
(when-not (empty? svg-values)
[:& svg-attrs-menu {:ids ids :values svg-values}])
[:> svg-attrs-menu* {:ids ids :values svg-values}])
[:> exports-menu* {:type type
:ids ids

View File

@ -20,10 +20,10 @@
[app.common.types.token :as tt]
[app.common.weak :as weak]
[app.main.refs :as refs]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-attrs blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-attrs blur-menu*]]
[app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu*]]
[app.main.ui.workspace.sidebar.options.menus.component :refer [component-menu*]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu*]]
[app.main.ui.workspace.sidebar.options.menus.exports :refer [exports-attrs exports-menu*]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill]
[app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu*]]
@ -31,7 +31,7 @@
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [select-measure-keys measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-attrs shadow-menu*]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu*]]
[app.main.ui.workspace.sidebar.options.menus.text :as ot]
[rumext.v2 :as mf]))
@ -478,7 +478,7 @@
:values layout-item-values}])
(when-not (or (empty? constraint-ids) ^boolean is-layout-child?)
[:& constraints-menu {:ids constraint-ids :values constraint-values}])
[:> constraints-menu* {:ids constraint-ids :values constraint-values}])
(when-not (empty? text-ids)
[:> ot/text-menu*
@ -494,12 +494,12 @@
:applied-tokens fill-tokens}])
(when-not (empty? stroke-ids)
[:& stroke-menu {:type type
:ids stroke-ids
:show-caps show-caps?
:values stroke-values
:disable-stroke-style has-text?
:applied-tokens stroke-tokens}])
[:> stroke-menu* {:type type
:ids stroke-ids
:show-caps show-caps?
:values stroke-values
:disable-stroke-style has-text?
:applied-tokens stroke-tokens}])
(when-not (empty? shapes)
[:> color-selection-menu*
@ -514,7 +514,7 @@
:values (get shadow-values :shadow)}])
(when-not (empty? blur-ids)
[:& blur-menu {:type type :ids blur-ids :values blur-values}])
[:> blur-menu* {:type type :ids blur-ids :values blur-values}])
(when-not (empty? exports-ids)
[:> exports-menu* {:type type

View File

@ -9,8 +9,8 @@
[app.common.data.macros :as dm]
[app.common.types.shape.layout :as ctl]
[app.main.refs :as refs]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu*]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu*]]
[app.main.ui.workspace.sidebar.options.menus.exports :refer [exports-menu* exports-attrs]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill]
[app.main.ui.workspace.sidebar.options.menus.grid-cell :as grid-cell]
@ -19,8 +19,8 @@
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu*]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu*]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu*]]
[rumext.v2 :as mf]))
(mf/defc options*
@ -117,8 +117,8 @@
:shape shape}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
[:& constraints-menu {:ids ids
:values constraint-values}])
[:> constraints-menu* {:ids ids
:values constraint-values}])
[:> fill/fill-menu*
{:ids ids
@ -126,16 +126,16 @@
:values shape
:applied-tokens applied-tokens}]
[:& stroke-menu {:ids ids
:type type
:show-caps true
:values stroke-values
:applied-tokens applied-tokens}]
[:> stroke-menu* {:ids ids
:type type
:show-caps true
:values stroke-values
:applied-tokens applied-tokens}]
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
[:& blur-menu {:ids ids
:values (select-keys shape [:blur])}]
[:& svg-attrs-menu {:ids ids
:values (select-keys shape [:svg-attrs])}]
[:> blur-menu* {:ids ids
:values (select-keys shape [:blur])}]
[:> svg-attrs-menu* {:ids ids
:values (select-keys shape [:svg-attrs])}]
[:> exports-menu* {:type type
:ids ids
:shapes shapes

View File

@ -9,8 +9,8 @@
[app.common.data.macros :as dm]
[app.common.types.shape.layout :as ctl]
[app.main.refs :as refs]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu*]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu*]]
[app.main.ui.workspace.sidebar.options.menus.exports :refer [exports-menu* exports-attrs]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill]
[app.main.ui.workspace.sidebar.options.menus.grid-cell :as grid-cell]
@ -19,8 +19,8 @@
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu*]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu*]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu*]]
[rumext.v2 :as mf]))
(mf/defc options*
@ -117,8 +117,8 @@
:shape shape}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
[:& constraints-menu {:ids ids
:values constraint-values}])
[:> constraints-menu* {:ids ids
:values constraint-values}])
[:> fill/fill-menu*
{:ids ids
@ -126,18 +126,18 @@
:values shape
:applied-tokens applied-tokens}]
[:& stroke-menu {:ids ids
:type type
:values stroke-values
:applied-tokens applied-tokens}]
[:> stroke-menu* {:ids ids
:type type
:values stroke-values
:applied-tokens applied-tokens}]
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
[:& blur-menu {:ids ids
:values (select-keys shape [:blur])}]
[:> blur-menu* {:ids ids
:values (select-keys shape [:blur])}]
[:& svg-attrs-menu {:ids ids
:values (select-keys shape [:svg-attrs])}]
[:> svg-attrs-menu* {:ids ids
:values (select-keys shape [:svg-attrs])}]
[:> exports-menu* {:type type
:ids ids
:shapes shapes

View File

@ -11,8 +11,8 @@
[app.common.types.color :as cc]
[app.common.types.shape.layout :as ctl]
[app.main.refs :as refs]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu*]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu*]]
[app.main.ui.workspace.sidebar.options.menus.exports :refer [exports-menu* exports-attrs]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill]
[app.main.ui.workspace.sidebar.options.menus.grid-cell :as grid-cell]
@ -20,8 +20,8 @@
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu*]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu*]]
[app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu*]]
[cuerdas.core :as str]
[rumext.v2 :as mf]))
@ -184,8 +184,8 @@
:shape shape}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
[:& constraints-menu {:ids ids
:values constraint-values}])
[:> constraints-menu* {:ids ids
:values constraint-values}])
[:> fill/fill-menu*
{:ids ids
@ -193,18 +193,18 @@
:values fill-values
:applied-tokens applied-tokens}]
[:& stroke-menu {:ids ids
:type type
:values stroke-values
:applied-tokens applied-tokens}]
[:> stroke-menu* {:ids ids
:type type
:values stroke-values
:applied-tokens applied-tokens}]
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
[:& blur-menu {:ids ids
:values (select-keys shape [:blur])}]
[:> blur-menu* {:ids ids
:values (select-keys shape [:blur])}]
[:& svg-attrs-menu {:ids ids
:values (select-keys shape [:svg-attrs])}]
[:> svg-attrs-menu* {:ids ids
:values (select-keys shape [:svg-attrs])}]
[:> exports-menu* {:type type
:ids ids
:shapes shapes

View File

@ -14,9 +14,9 @@
[app.main.features :as features]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu*]]
[app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu*]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu*]]
[app.main.ui.workspace.sidebar.options.menus.exports :refer [exports-menu* exports-attrs]]
[app.main.ui.workspace.sidebar.options.menus.fill :as fill]
[app.main.ui.workspace.sidebar.options.menus.grid-cell :as grid-cell]
@ -25,7 +25,7 @@
[app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]]
[app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu*]]
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu*]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]]
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu*]]
[app.main.ui.workspace.sidebar.options.menus.text :refer [text-menu*]]
[rumext.v2 :as mf]))
@ -172,7 +172,7 @@
:shape shape}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
[:& constraints-menu
[:> constraints-menu*
{:ids ids
:values (select-keys shape constraint-attrs)}])
@ -188,11 +188,11 @@
:values fill-values
:applied-tokens applied-tokens}]
[:& stroke-menu {:ids ids
:type type
:values stroke-values
:disable-stroke-style true
:applied-tokens applied-tokens}]
[:> stroke-menu* {:ids ids
:type type
:values stroke-values
:disable-stroke-style true
:applied-tokens applied-tokens}]
(when (= :multiple (:fills fill-values))
[:> color-selection-menu*
@ -203,7 +203,7 @@
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
[:& blur-menu
[:> blur-menu*
{:ids ids
:values (select-keys shape [:blur])}]

View File

@ -14,11 +14,11 @@
[app.util.i18n :refer [tr]]
[rumext.v2 :as mf]))
(mf/defc text-palette-ctx-menu
[{:keys [show-menu? close-menu on-select-palette selected]}]
(mf/defc text-palette-ctx-menu*
[{:keys [show-menu close-menu on-select-palette selected]}]
(let [typographies (mf/deref refs/workspace-file-typography)
libraries (mf/deref refs/libraries)]
[:& dropdown {:show show-menu?
[:& dropdown {:show show-menu
:on-close close-menu}
[:ul {:class (stl/css :text-context-menu)}
(for [[idx cur-library] (map-indexed vector (vals libraries))]

View File

@ -27,7 +27,7 @@
[potok.v2.core :as ptk]
[rumext.v2 :as mf]))
(mf/defc image-upload
(mf/defc image-upload*
{::mf/wrap [mf/memo]}
[]
(let [ref (mf/use-ref nil)
@ -181,7 +181,7 @@
:data-tool "text"}
deprecated-icon/text]]
[:& image-upload]
[:> image-upload*]
[:li
[:button

View File

@ -30,7 +30,7 @@
[app.main.ui.workspace.shapes :as shapes]
[app.main.ui.workspace.shapes.path.editor :refer [path-editor*]]
[app.main.ui.workspace.shapes.text.editor :as editor-v1]
[app.main.ui.workspace.shapes.text.text-edition-outline :refer [text-edition-outline]]
[app.main.ui.workspace.shapes.text.text-edition-outline :refer [text-edition-outline*]]
[app.main.ui.workspace.shapes.text.v2-editor :as editor-v2]
[app.main.ui.workspace.shapes.text.viewport-texts-html :as stvh]
[app.main.ui.workspace.top-toolbar :refer [top-toolbar*]]
@ -489,7 +489,7 @@
:on-context-menu on-menu-selected}])
(when show-text-editor?
[:& text-edition-outline
[:> text-edition-outline*
{:shape (get base-objects edition)
:zoom zoom
:modifiers modifiers}])

View File

@ -28,7 +28,7 @@
[app.main.ui.measurements :as msr]
[app.main.ui.workspace.shapes.path.editor :refer [path-editor*]]
[app.main.ui.workspace.shapes.text.editor :as editor-v1]
[app.main.ui.workspace.shapes.text.text-edition-outline :refer [text-edition-outline]]
[app.main.ui.workspace.shapes.text.text-edition-outline :refer [text-edition-outline*]]
[app.main.ui.workspace.shapes.text.v2-editor :as editor-v2]
[app.main.ui.workspace.shapes.text.v3-editor :as editor-v3]
[app.main.ui.workspace.top-toolbar :refer [top-toolbar*]]
@ -587,7 +587,7 @@
:on-context-menu on-menu-selected}])
(when show-text-editor?
[:& text-edition-outline
[:> text-edition-outline*
{:shape (get base-objects edition)
:zoom zoom}])

View File

@ -7591,11 +7591,14 @@ msgid "workspace.plugins.empty-plugins"
msgstr "No plugins installed yet"
#: src/app/main/ui/workspace/plugins.cljs:193
msgid "workspace.plugins.error.manifest"
msgstr "The plugin manifest is incorrect."
msgid "workspace.plugins.error.manifest"
msgstr "The plugin manifest is incorrect."
msgid "plugins.validation.message"
msgstr "Field %s is invalid: %s"
#: src/app/main/data/plugins.cljs:105, src/app/main/ui/workspace/main_menu.cljs:766, src/app/main/ui/workspace/plugins.cljs:84
msgid "workspace.plugins.error.need-editor"
msgid "workspace.plugins.error.need-editor"
msgstr "You need to be an editor to use this plugin"
#: src/app/main/ui/workspace/plugins.cljs:189

View File

@ -374,7 +374,7 @@ Applying tokens:
- The actual shape properties that the tokens control will reflect the token's resolved value.
Removing tokens:
Simply set the respective property directly - token binding is automatically removed, e.g.
Simply set the respective property directly - token binding is automatically removed, e.g.
shape.fills = [{ fillColor: "#000000", fillOpacity: 1 }]; // Removes fill token
# Visual Inspection of Designs
@ -386,7 +386,7 @@ For many tasks, it can be critical to visually inspect the design. Remember to u
* When transferring styles from a Penpot design to code, make sure that you strictly adhere to the design.
NEVER make assumptions about missing values and don't get overly creative (e.g. don't pick your own colours and stick to
non-creative defaults such as white/black if you are lacking information).
* When creating new designs,
* When creating new designs,
- ensure a clean internal structure by applying flex and grid layouts when appropriate
- ensure proper semantic naming of elements.