0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-04-09 21:41:23 -05:00

Remove menu options and shortcuts actions over variants

This commit is contained in:
Pablo Alba 2025-02-25 10:11:14 +01:00 committed by GitHub
parent ab7781b4fa
commit 6d40166de7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 185 additions and 138 deletions

View file

@ -11,6 +11,7 @@
[app.common.files.helpers :as cph]
[app.common.geom.shapes :as gsh]
[app.common.svg.path.shapes-to-path :as stp]
[app.common.types.component :as ctc]
[app.common.types.container :as ctn]
[app.common.types.shape :as cts]
[app.common.types.shape.layout :as ctl]
@ -99,6 +100,7 @@
shapes (->> ordered-indexes
(map (d/getf objects))
(remove cph/frame-shape?)
(remove ctc/is-variant?)
(remove #(ctn/has-any-copy-parent? objects %)))]
(when-not (empty? shapes)

View file

@ -188,7 +188,9 @@
(->> ids
(cfh/clean-loops objects)
(remove #(ctn/has-any-copy-parent? objects (get objects %)))
(shapes-for-grouping objects))
(shapes-for-grouping objects)
(remove ctk/is-variant?))
parents (into #{} (map :parent-id) shapes)]
(when-not (empty? shapes)
(let [[group changes]

View file

@ -172,47 +172,55 @@
is-mask? (and single? has-mask?)
has-component? (some true? (map ctc/instance-root? selected-shapes))
is-component? (and single? has-component?)
has-variant? (some ctc/is-variant? selected-shapes)
new-shape-id (uuid/next)
undo-id (js/Symbol)]
(rx/concat
(rx/of (dwu/start-undo-transaction undo-id))
(if (and is-group? (not is-component?) (not is-mask?))
;; Create layout from a group:
;; When creating a layout from a group we remove the group and create the layout with its children
(let [parent-id (:parent-id (first selected-shapes))
shapes-ids (:shapes (first selected-shapes))
ordered-ids (into (d/ordered-set) shapes-ids)
group-index (cfh/get-index-replacement selected objects)]
(if has-variant?
(rx/empty)
(rx/concat
(rx/of (dwu/start-undo-transaction undo-id))
(if (and is-group? (not is-component?) (not is-mask?))
;; Create layout from a group:
;; When creating a layout from a group we remove the group and create the layout with its children
(let [parent-id (:parent-id (first selected-shapes))
shapes-ids (:shapes (first selected-shapes))
ordered-ids (into (d/ordered-set) shapes-ids)
group-index (cfh/get-index-replacement selected objects)]
(rx/of
(dwse/select-shapes ordered-ids)
(dwsh/create-artboard-from-selection new-shape-id parent-id group-index (:name (first selected-shapes)))
(cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1})
(create-layout-from-id new-shape-id type)
(dwsh/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto))
(dwsh/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix))
(dwsh/delete-shapes page-id selected)
(ptk/data-event :layout/update {:ids [new-shape-id]})
(dwu/commit-undo-transaction undo-id)))
;; Create Layout from selection
(rx/of
(dwse/select-shapes ordered-ids)
(dwsh/create-artboard-from-selection new-shape-id parent-id group-index (:name (first selected-shapes)))
(dwsh/create-artboard-from-selection new-shape-id)
(cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1})
(create-layout-from-id new-shape-id type)
(dwsh/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto))
(dwsh/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix))
(dwsh/delete-shapes page-id selected)
(ptk/data-event :layout/update {:ids [new-shape-id]})
(dwu/commit-undo-transaction undo-id)))
(dwsh/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix))))
;; Create Layout from selection
(rx/of
(dwsh/create-artboard-from-selection new-shape-id)
(cl/remove-all-fills [new-shape-id] {:color clr/black :opacity 1})
(create-layout-from-id new-shape-id type)
(dwsh/update-shapes [new-shape-id] #(assoc % :layout-item-h-sizing :auto :layout-item-v-sizing :auto))
(dwsh/update-shapes selected #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix))))
(rx/of (ptk/data-event :layout/update {:ids [new-shape-id]})
(dwu/commit-undo-transaction undo-id)))))))
(rx/of (ptk/data-event :layout/update {:ids [new-shape-id]})
(dwu/commit-undo-transaction undo-id))))))))
(defn remove-layout
[ids]
(ptk/reify ::remove-shape-layout
ptk/WatchEvent
(watch [_ _ _]
(let [undo-id (js/Symbol)]
(watch [_ state _]
(let [objects (dsh/lookup-page-objects state)
ids (->> ids
(remove #(->> %
(get objects)
(ctc/is-variant?))))
undo-id (js/Symbol)]
(rx/of
(dwu/start-undo-transaction undo-id)
(dwsh/update-shapes ids #(apply dissoc % layout-keys))
@ -234,11 +242,12 @@
selected-shapes (map (d/getf objects) selected)
single? (= (count selected-shapes) 1)
is-frame? (= :frame (:type (first selected-shapes)))
is-variant-cont? (ctc/is-variant-container? (first selected-shapes))
undo-id (js/Symbol)]
(rx/of
(dwu/start-undo-transaction undo-id)
(if (and single? is-frame?)
(if (and single? is-frame? (not is-variant-cont?))
(create-layout-from-id (first selected) type :from-frame? true)
(create-layout-from-selection type))
(dwu/commit-undo-transaction undo-id))))))

View file

@ -13,6 +13,7 @@
[app.common.files.shapes-helpers :as cfsh]
[app.common.logic.shapes :as cls]
[app.common.schema :as sm]
[app.common.types.component :as ctc]
[app.common.types.container :as ctn]
[app.common.types.shape :as cts]
[app.common.types.shape-tree :as ctst]
@ -248,7 +249,10 @@
objects (dsh/lookup-page-objects state page-id)
selected (->> (dsh/lookup-selected state)
(cfh/clean-loops objects)
(remove #(ctn/has-any-copy-parent? objects (get objects %))))
(remove #(ctn/has-any-copy-parent? objects (get objects %)))
(remove #(->> %
(get objects)
(ctc/is-variant?))))
changes (-> (pcb/empty-changes it page-id)
(pcb/with-objects objects))

View file

@ -968,7 +968,10 @@
(watch [_ state _]
(let [objects (dsh/lookup-page-objects state)
selected (or ids (dsh/lookup-selected state {:omit-blocked? true}))
shapes (map #(get objects %) selected)
shapes (->> selected
(map (d/getf objects))
(remove ctk/is-variant-container?))
selected (->> shapes (map :id))
selrect (gsh/shapes->rect shapes)
center (grc/rect->center selrect)
modifiers (dwm/create-modif-tree selected (ctm/resize-modifiers (gpt/point -1.0 1.0) center))]
@ -983,7 +986,10 @@
(watch [_ state _]
(let [objects (dsh/lookup-page-objects state)
selected (or ids (dsh/lookup-selected state {:omit-blocked? true}))
shapes (map #(get objects %) selected)
shapes (->> selected
(map #(get objects %))
(remove ctk/is-variant-container?))
selected (->> shapes (map :id))
selrect (gsh/shapes->rect shapes)
center (grc/rect->center selrect)
modifiers (dwm/create-modif-tree selected (ctm/resize-modifiers (gpt/point 1.0 -1.0) center))]

View file

@ -23,7 +23,7 @@
(mf/defc input-with-values*
{::mf/props :obj
::mf/schema schema:input-with-values}
[{:keys [name values on-blur]}]
[{:keys [name values on-blur] :rest props}]
(let [editing* (mf/use-state false)
editing? (deref editing*)
input-ref (mf/use-ref)
@ -39,11 +39,10 @@
(mf/use-fn
(mf/deps on-blur)
(fn [event]
(let [new-name (dom/get-target-val event)]
(dom/stop-propagation event)
(reset! editing* false)
(when on-blur
(on-blur new-name)))))
(dom/stop-propagation event)
(reset! editing* false)
(when on-blur
(on-blur event))))
on-focus
(mf/use-fn
(fn [event]
@ -57,18 +56,19 @@
esc? (kbd/esc? event)
node (dom/get-target event)]
(when ^boolean enter? (dom/blur! node))
(when ^boolean esc? (dom/blur! node)))))]
(when ^boolean esc? (dom/blur! node)))))
props (mf/spread-props props {:ref input-ref
:class (stl/css :input-with-values-editing)
:default-value name
:auto-focus true
:on-focus on-focus
:on-blur on-stop-edit
:on-key-down handle-key-down})]
(if editing?
[:div {:class (stl/css :input-with-values-edit-container)}
[:> input*
{:ref input-ref
:class (stl/css :input-with-values-editing)
:default-value name
:auto-focus true
:on-focus on-focus
:on-blur on-stop-edit
:on-key-down handle-key-down}]]
[:> input* props]]
[:div {:class (stl/css :input-with-values-container :input-with-values-grid)
:title title :on-click on-edit}
[:span {:class (stl/css :input-with-values-name)} name]

View file

@ -13,7 +13,7 @@ The `input-with-values*` acts as an input with an addition of a series of values
## Technical notes
* You need to pass the mandatory string properties `name` and `values`
* You can pass a function property `on-blur` that will be called with the new value when the component lost focus (including when the user press enter or esc)
* You can pass a function property `on-blur` that will be called with the blur event when the component lost focus (including when the user press enter or esc)
```clj
[:> input-with-values*

View file

@ -317,11 +317,12 @@
{::mf/props :obj
::mf/private true}
[{:keys [shapes]}]
(let [multiple? (> (count shapes) 1)
single? (= (count shapes) 1)
(let [multiple? (> (count shapes) 1)
single? (= (count shapes) 1)
objects (deref refs/workspace-page-objects)
any-in-copy? (some true? (map #(ctn/has-any-copy-parent? objects %) shapes))
objects (deref refs/workspace-page-objects)
any-in-copy? (some #(ctn/has-any-copy-parent? objects %) shapes)
any-is-variant? (some ctk/is-variant? shapes)
;; components can't be ungrouped
has-frame? (->> shapes (d/seek #(and (cfh/frame-shape? %) (not (ctk/instance-head? %)) (not (ctk/is-variant-container? %)))))
@ -340,7 +341,7 @@
#(st/emit! (dwsh/create-artboard-from-selection))]
[:*
(when (not any-in-copy?)
(when (not (or any-in-copy? any-is-variant?))
[:*
(when (or has-bool? has-group? has-mask? has-frame?)
[:> menu-entry* {:title (tr "workspace.shape.menu.ungroup")
@ -503,6 +504,8 @@
has-grid?
(and single? (every? ctl/grid-layout? shapes))
any-is-variant? (some ctk/is-variant? shapes)
on-add-layout
(mf/use-fn
(fn [event]
@ -532,16 +535,17 @@
:shortcut (sc/get-tooltip :toggle-layout-grid)
:on-click on-remove-layout}])]
[:div
[:> menu-separator* {}]
[:> menu-entry* {:title (tr "workspace.shape.menu.add-flex")
:shortcut (sc/get-tooltip :toggle-layout-flex)
:value "flex"
:on-click on-add-layout}]
[:> menu-entry* {:title (tr "workspace.shape.menu.add-grid")
:shortcut (sc/get-tooltip :toggle-layout-grid)
:value "grid"
:on-click on-add-layout}]]))]))
(when (or single? (not any-is-variant?))
[:div
[:> menu-separator* {}]
[:> menu-entry* {:title (tr "workspace.shape.menu.add-flex")
:shortcut (sc/get-tooltip :toggle-layout-flex)
:value "flex"
:on-click on-add-layout}]
[:> menu-entry* {:title (tr "workspace.shape.menu.add-grid")
:shortcut (sc/get-tooltip :toggle-layout-grid)
:value "grid"
:on-click on-add-layout}]])))]))
(mf/defc context-menu-component*
{:mf/private true}
@ -593,6 +597,7 @@
[{:keys [mdata]}]
(let [{:keys [disable-booleans disable-flatten]} mdata
shapes (mf/deref refs/selected-objects)
is-not-variant-container? (->> shapes (d/seek #(not (ctk/is-variant-container? %))))
props (mf/props
{:shapes shapes
:disable-booleans disable-booleans
@ -601,7 +606,8 @@
[:*
[:> context-menu-edit* props]
[:> context-menu-layer-position* props]
[:> context-menu-flip* props]
(when is-not-variant-container?
[:> context-menu-flip* props])
[:> context-menu-thumbnail* props]
[:> context-menu-rename* props]
[:> context-menu-group* props]
@ -609,7 +615,8 @@
[:> context-menu-path* props]
[:> context-menu-layer-options* props]
[:> context-menu-prototype* props]
[:> context-menu-layout* props]
(when is-not-variant-container?
[:> context-menu-layout* props])
[:> context-menu-component* props]
[:> context-menu-delete* props]])))

View file

@ -740,8 +740,7 @@
(mf/defc variant-menu*
[{:keys [shapes]}]
(let [;; TODO check multi. What is shown? User can change properties like width?
multi (> (count shapes) 1)
(let [multi (> (count shapes) 1)
shape (first shapes)
shape-name (:name shape)
@ -757,13 +756,15 @@
first-variant (get objects (first (:shapes shape)))
variant-id (:variant-id first-variant)
properties (->> (dwv/find-related-components data objects variant-id)
(mapcat :variant-properties)
(group-by :name)
(map (fn [[k v]]
{:name k
:values (distinct
(map #(if (str/empty? (:value %)) "--" (:value %)) v))})))
properties (mf/with-memo [data objects variant-id]
(->> (dwv/find-related-components data objects variant-id)
(mapcat :variant-properties)
(group-by :name)
(map-indexed (fn [index [k v]]
{:name k
:pos index
:values (distinct
(map #(if (str/empty? (:value %)) "--" (:value %)) v))}))))
menu-open* (mf/use-state false)
menu-open? (deref menu-open*)
@ -790,15 +791,22 @@
update-property-name
(mf/use-fn
(mf/deps variant-id)
(fn [pos new-name]
(st/emit! (dwv/update-property-name variant-id pos new-name))))
(fn [event]
(let [new-name (dom/get-target-val event)
pos (-> (dom/get-current-target event)
(dom/get-data "position")
int)]
(st/emit! (dwv/update-property-name variant-id pos new-name)))))
remove-property
(mf/use-fn
(mf/deps variant-id)
(fn [pos]
(when (> (count properties) 1)
(st/emit! (dwv/remove-property variant-id pos)))))]
(mf/deps variant-id properties)
(fn [event]
(let [pos (-> (dom/get-current-target event)
(dom/get-data "position")
int)]
(when (> (count properties) 1)
(st/emit! (dwv/remove-property variant-id pos))))))]
(when (seq shapes)
[:div {:class (stl/css :element-set)}
[:div {:class (stl/css :element-title)}
@ -839,13 +847,18 @@
:on-close on-menu-close
:menu-entries menu-entries
:main-instance true}]])]
[:*
(for [[pos property] (map vector (range) properties)]
(let [val (str/join ", " (:values property))]
[:div {:key (str (:id shape) (:name property)) :class (stl/css :variant-property-row)}
[:> input-with-values* {:name (:name property) :values val :on-blur (partial update-property-name pos)}]
[:> icon-button* {:variant "ghost"
:aria-label (tr "workspace.shape.menu.remove-variant-property")
:on-click (partial remove-property pos)
:icon "remove"
:disabled (<= (count properties) 1)}]]))]]])))
(when-not multi
[:*
(for [property properties]
(let [val (str/join ", " (:values property))]
[:div {:key (str (:id shape) (:name property)) :class (stl/css :variant-property-row)}
[:> input-with-values* {:name (:name property)
:values val
:data-position (:pos property)
:on-blur update-property-name}]
[:> icon-button* {:variant "ghost"
:aria-label (tr "workspace.shape.menu.remove-variant-property")
:on-click remove-property
:data-position (:pos property)
:icon "remove"
:disabled (<= (count properties) 1)}]]))])]])))

View file

@ -33,6 +33,9 @@
ids (mf/with-memo [shape-id]
[shape-id])
shapes (mf/with-memo [shape]
[shape])
stroke-values (select-keys shape stroke-attrs)
layer-values (select-keys shape layer-attrs)
measure-values (select-measure-keys shape)
@ -71,58 +74,59 @@
variants? (features/use-feature "variants/v1")
is-variant? (when variants? (:is-variant-container shape))]
(if is-variant?
[:> variant-menu* {:shapes [shape]}]
[:*
[:& layer-menu {:ids ids
:type shape-type
:values layer-values}]
[:> measures-menu* {:ids ids
:values measure-values
:type shape-type
:shape shape}]
[:*
[:& layer-menu {:ids ids
:type shape-type
:values layer-values}]
[:> measures-menu* {:ids ids
:values measure-values
:type shape-type
:shape shape}]
[:& component-menu {:shapes [shape]}]
[:& component-menu {:shapes shapes}]
[:& layout-container-menu
{:type shape-type
:ids [(:id shape)]
:values layout-container-values
:multiple false}]
(when is-variant?
[:> variant-menu* {:shapes shapes}])
(when (and (= (count ids) 1) is-layout-child? is-grid-parent?)
[:& grid-cell/options
{:shape (first parents)
:cell (ctl/get-cell-by-shape-id (first parents) (first ids))}])
[:& layout-container-menu
{:type shape-type
:ids ids
:values layout-container-values
:multiple false}]
(when (or is-layout-child? is-layout-container?)
[:& layout-item-menu
{:ids ids
:type shape-type
:values layout-item-values
:is-flex-parent? is-flex-parent?
:is-grid-parent? is-grid-parent?
:is-flex-layout? is-flex-layout?
:is-grid-layout? is-grid-layout?
:is-layout-child? is-layout-child?
:is-layout-container? is-layout-container?
:shape shape}])
(when (and (= (count ids) 1) is-layout-child? is-grid-parent?)
[:& grid-cell/options
{:shape (first parents)
:cell (ctl/get-cell-by-shape-id (first parents) (first ids))}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
[:& constraints-menu {:ids ids
:values constraint-values}])
(when (or is-layout-child? is-layout-container?)
[:& layout-item-menu
{:ids ids
:type shape-type
:values layout-item-values
:is-flex-parent? is-flex-parent?
:is-grid-parent? is-grid-parent?
:is-flex-layout? is-flex-layout?
:is-grid-layout? is-grid-layout?
:is-layout-child? is-layout-child?
:is-layout-container? is-layout-container?
:shape shape}])
[:& fill-menu {:ids ids
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
[:& constraints-menu {:ids ids
:values constraint-values}])
[:& fill-menu {:ids ids
:type shape-type
:values (select-keys shape fill-attrs-shape)}]
[:& stroke-menu {:ids ids
:type shape-type
:values (select-keys shape fill-attrs-shape)}]
[:& stroke-menu {:ids ids
:type shape-type
:values stroke-values}]
[:> color-selection-menu* {:type shape-type
:shapes shapes-with-children
:file-id file-id
:libraries shared-libs}]
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
[:& blur-menu {:ids ids
:values (select-keys shape [:blur])}]
[:& frame-grid {:shape shape}]])))
:values stroke-values}]
[:> color-selection-menu* {:type shape-type
:shapes shapes-with-children
:file-id file-id
:libraries shared-libs}]
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
[:& blur-menu {:ids ids
:values (select-keys shape [:blur])}]
[:& frame-grid {:shape shape}]]))