0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-13 10:38:13 -05:00

Merge pull request #1430 from penpot/bugfixes

Bugfixes
This commit is contained in:
Eva Marco 2022-01-03 10:46:22 +01:00 committed by GitHub
commit fdd66bd513
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 353 additions and 302 deletions

View file

@ -16,6 +16,10 @@
- Fix problems when exporting all artboards [Taiga #2234](https://tree.taiga.io/project/penpot/issue/2234).
- Fix problems with team management [#1353](https://github.com/penpot/penpot/issues/1353)
- Fix problem when importing in shared libraries [#1362](https://github.com/penpot/penpot/issues/1362)
- Fix problem with join nodes [#1422](https://github.com/penpot/penpot/issues/1422)
- After team onboarding importing a file will import into the team drafts [Taiga #2408](https://tree.taiga.io/project/penpot/issue/2408)
- Fix problem exporting shapes from handoff mode [Taiga #2386](https://tree.taiga.io/project/penpot/issue/2386)
- Fix lock/hide elements in context menu when multiples shapes selected [Taiga #2340](https://tree.taiga.io/project/penpot/issue/2340)
### :arrow_up: Deps updates
### :heart: Community contributions by (Thank you!)

View file

@ -1,6 +1,7 @@
$width-settings-bar: 16rem;
.handoff-layout {
height: 100vh;
display: grid;
grid-template-rows: 40px auto;
grid-template-columns: 1fr;

View file

@ -18,7 +18,6 @@
top: 40px;
width: 240px;
z-index: 12;
padding: $size-1 0;
li {
align-items: center;

View file

@ -1227,8 +1227,8 @@
;; --- Update Shape Flags
(defn update-shape-flags
[id {:keys [blocked hidden] :as flags}]
(s/assert ::us/uuid id)
[ids {:keys [blocked hidden] :as flags}]
(us/verify (s/coll-of ::us/uuid) ids)
(s/assert ::shape-attrs flags)
(ptk/reify ::update-shape-flags
ptk/WatchEvent
@ -1238,9 +1238,8 @@
(cond-> obj
(boolean? blocked) (assoc :blocked blocked)
(boolean? hidden) (assoc :hidden hidden)))
objects (wsh/lookup-page-objects state)
ids (into [id] (cp/get-children id objects))]
ids (into ids (->> ids (mapcat #(cp/get-children % objects))))]
(rx/of (dch/update-shapes ids update-fn))))))
(defn toggle-visibility-selected
@ -1349,16 +1348,16 @@
:typographies #{}}))))
(defn go-to-component
[objs]
[component-id]
(ptk/reify ::set-workspace-layout-component
IDeref
(-deref [_] {:layout :assets})
ptk/WatchEvent
(watch [_ state _]
(let [project-id (get-in state [:workspace-project :id])
file-id (get-in state [:workspace-file :id])
page-id (get state :current-page-id)
component-id (get (first objs) :component-id)
pparams {:file-id file-id :project-id project-id}
qparams {:page-id page-id :layout :assets}]
(rx/of (rt/nav :workspace pparams qparams)
@ -1367,8 +1366,7 @@
(select-single-asset component-id :components))))
ptk/EffectEvent
(effect [_ _ _]
(let [component-id (get (first objs) :component-id)
wrapper-id (str "component-shape-id-" component-id)]
(let [wrapper-id (str "component-shape-id-" component-id)]
(tm/schedule-on-idle #(dom/scroll-into-view-if-needed! (dom/get-element wrapper-id)))))))
(def go-to-file
@ -1422,53 +1420,37 @@
(s/def ::point gpt/point?)
(defn show-context-menu
[{:keys [position shape] :as params}]
[{:keys [position] :as params}]
(us/verify ::point position)
(us/verify (s/nilable ::cp/minimal-shape) shape)
(ptk/reify ::show-context-menu
ptk/UpdateEvent
(update [_ state]
(let [selected (wsh/lookup-selected state)
objects (wsh/lookup-page-objects state)
selected-with-children
(into []
(mapcat #(cp/get-object-with-children % objects))
selected)
head (get objects (first selected))
first-not-group-like?
(and (= (count selected) 1)
(not (contains? #{:group :bool} (:type head))))
has-invalid-shapes? (->> selected-with-children
(some (comp #{:frame :text} :type)))
disable-booleans? (or (empty? selected) has-invalid-shapes? first-not-group-like?)
disable-flatten? (or (empty? selected) has-invalid-shapes?)
mdata
(-> params
(assoc :disable-booleans? disable-booleans?)
(assoc :disable-flatten? disable-flatten?)
(cond-> (some? shape)
(assoc :selected selected)))]
(assoc-in state [:workspace-local :context-menu] mdata)))))
(assoc-in state [:workspace-local :context-menu] params))))
(defn show-shape-context-menu
[{:keys [position shape] :as params}]
(us/verify ::point position)
(us/verify ::cp/minimal-shape shape)
[{:keys [shape] :as params}]
(us/verify (s/nilable ::cp/minimal-shape) shape)
(ptk/reify ::show-shape-context-menu
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)]
(let [selected (wsh/lookup-selected state)
objects (wsh/lookup-page-objects state)
all-selected (into [] (mapcat #(cp/get-object-with-children % objects)) selected)
head (get objects (first selected))
not-group-like? (and (= (count selected) 1)
(not (contains? #{:group :bool} (:type head))))
no-bool-shapes? (->> all-selected (some (comp #{:frame :text} :type)))]
(rx/concat
(when-not (selected (:id shape))
(rx/of (dws/select-shape (:id shape))))
(rx/of (show-context-menu params)))))))
(when (and (some? shape) (not (contains? selected (:id shape))))
(rx/of (dws/select-shape (:id shape))))
(rx/of (show-context-menu
(-> params
(assoc
:disable-booleans? (or no-bool-shapes? not-group-like?)
:disable-flatten? no-bool-shapes?
:selected (conj selected (:id shape)))))))))))
(def hide-context-menu
(ptk/reify ::hide-context-menu

View file

@ -635,6 +635,20 @@
:origin it
:file-id file-id})))))))
(defn update-component-sync
[shape-id file-id]
(ptk/reify ::update-component-sync
ptk/WatchEvent
(watch [_ state _]
(let [current-file-id (:current-file-id state)]
(rx/of
(dwu/start-undo-transaction)
(update-component shape-id)
(sync-file current-file-id file-id)
(when (not= current-file-id file-id)
(sync-file file-id file-id))
(dwu/commit-undo-transaction))))))
(declare sync-file-2nd-stage)
(defn sync-file

View file

@ -184,11 +184,13 @@
is-not-blocked (fn [shape-id] (not (get-in state [:workspace-data
:pages-index page-id
:objects shape-id
:blocked] false)))]
(rx/of (->> new-selected
(filter is-not-blocked)
(into lks/empty-linked-set)
(select-shapes)))))))
:blocked] false)))
selected-ids (into lks/empty-linked-set
(comp (filter some?)
(filter is-not-blocked))
new-selected)]
(rx/of (select-shapes selected-ids))))))
(defn deselect-all
"Clear all possible state of drawing, edition

View file

@ -61,8 +61,9 @@
::mf/register-as :onboarding-templates}
;; NOTE: the project usually comes empty, it only comes fullfilled
;; when a user creates a new team just after signup.
[{:keys [project-id] :as props}]
(let [close-fn (mf/use-callback #(st/emit! (modal/hide)))
[props]
(let [project-id (unchecked-get props "project-id")
close-fn (mf/use-callback #(st/emit! (modal/hide)))
profile (mf/deref refs/profile)
project-id (or project-id (:default-project-id profile))]
[:div.modal-overlay

View file

@ -7,36 +7,17 @@
(ns app.main.ui.viewer.handoff.exports
(:require
[app.common.data :as d]
[app.main.data.messages :as dm]
[app.main.store :as st]
[app.main.ui.icons :as i]
[app.main.ui.workspace.sidebar.options.menus.exports :as we]
[app.util.dom :as dom]
[app.util.i18n :refer [tr]]
[beicon.core :as rx]
[rumext.alpha :as mf]))
(mf/defc exports
[{:keys [shape page-id file-id] :as props}]
(let [exports (mf/use-state (:exports shape []))
loading? (mf/use-state false)
on-download
(mf/use-callback
(mf/deps shape @exports)
(fn [event]
(dom/prevent-default event)
(swap! loading? not)
(->> (we/request-export (assoc shape :page-id page-id :file-id file-id) @exports)
(rx/subs
(fn [{:keys [status body] :as response}]
(js/console.log status body)
(if (= status 200)
(dom/trigger-download (:name shape) body)
(st/emit! (dm/error (tr "errors.unexpected-error")))))
(constantly nil)
(fn []
(swap! loading? not))))))
[on-download loading?] (we/use-download-export shape page-id file-id @exports)
add-export
(mf/use-callback
@ -118,10 +99,10 @@
i/minus]])
[:div.btn-icon-dark.download-button
{:on-click (when-not @loading? on-download)
:class (dom/classnames :btn-disabled @loading?)
:disabled @loading?}
(if @loading?
{:on-click (when-not loading? on-download)
:class (dom/classnames :btn-disabled loading?)
:disabled loading?}
(if loading?
(tr "workspace.options.exporting-object")
(tr "workspace.options.export-object"))]])]))

View file

@ -7,13 +7,13 @@
(ns app.main.ui.workspace.context-menu
"A workspace specific context menu (mouse right click)."
(:require
[app.common.data :as d]
[app.common.types.page-options :as cto]
[app.main.data.modal :as modal]
[app.main.data.workspace :as dw]
[app.main.data.workspace.interactions :as dwi]
[app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.shortcuts :as sc]
[app.main.data.workspace.undo :as dwu]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.dropdown :refer [dropdown]]
@ -85,95 +85,12 @@
[]
[:li.separator])
(mf/defc shape-context-menu
[{:keys [mdata] :as props}]
(let [{:keys [shape selected disable-booleans? disable-flatten?]} mdata
{:keys [id type]} shape
single? (= (count selected) 1)
multiple? (> (count selected) 1)
editable-shape? (#{:group :text :path} type)
is-group? (and (some? shape) (= :group type))
is-bool? (and (some? shape) (= :bool type))
options (mf/deref refs/workspace-page-options)
selected-objects (mf/deref refs/selected-objects)
flows (:flows options)
has-group? (some #(= :group (:type %)) selected-objects)
has-bool? (some #(= :bool (:type %)) selected-objects)
has-mask-group? (some #(:masked-group? %) selected-objects)
options-mode (mf/deref refs/options-mode)
set-bool
(fn [bool-type]
#(cond
(> (count selected) 1)
(st/emit! (dw/create-bool bool-type))
(and (= (count selected) 1) is-group?)
(st/emit! (dw/group-to-bool (:id shape) bool-type))
(and (= (count selected) 1) is-bool?)
(st/emit! (dw/change-bool-type (:id shape) bool-type))))
current-file-id (mf/use-ctx ctx/current-file-id)
do-duplicate (st/emitf (dw/duplicate-selected false))
do-delete (st/emitf dw/delete-selected)
do-copy (st/emitf (dw/copy-selected))
do-cut (st/emitf (dw/copy-selected) dw/delete-selected)
do-paste (st/emitf dw/paste)
do-bring-forward (st/emitf (dw/vertical-order-selected :up))
do-bring-to-front (st/emitf (dw/vertical-order-selected :top))
do-send-backward (st/emitf (dw/vertical-order-selected :down))
do-send-to-back (st/emitf (dw/vertical-order-selected :bottom))
do-show-shape (st/emitf (dw/update-shape-flags id {:hidden false}))
do-hide-shape (st/emitf (dw/update-shape-flags id {:hidden true}))
do-lock-shape (st/emitf (dw/update-shape-flags id {:blocked true}))
do-unlock-shape (st/emitf (dw/update-shape-flags id {:blocked false}))
do-add-flow (st/emitf (dwi/add-flow-selected-frame))
do-remove-flow #(st/emitf (dwi/remove-flow (:id %)))
do-create-group (st/emitf dw/group-selected)
do-remove-group (st/emitf dw/ungroup-selected)
do-mask-group (st/emitf dw/mask-group)
do-unmask-group (st/emitf dw/unmask-group)
do-flip-vertical (st/emitf (dw/flip-vertical-selected))
do-flip-horizontal (st/emitf (dw/flip-horizontal-selected))
do-add-component (st/emitf (dwl/add-component))
do-detach-component (st/emitf (dwl/detach-component id))
do-reset-component (st/emitf (dwl/reset-component id))
do-start-editing (fn []
;; We defer the execution so the mouse event won't close the editor
(timers/schedule #(st/emit! (dw/start-editing-selected))))
do-update-component (st/emitf
(dwu/start-undo-transaction)
(dwl/update-component id)
(dwl/sync-file current-file-id (:component-file shape))
(dwu/commit-undo-transaction))
confirm-update-remote-component (st/emitf
(dwl/update-component id)
(dwl/sync-file current-file-id
(:component-file shape))
(dwl/sync-file (:component-file shape)
(:component-file shape)))
do-update-remote-component (st/emitf (modal/show
{:type :confirm
:message ""
:title (tr "modals.update-remote-component.message")
:hint (tr "modals.update-remote-component.hint")
:cancel-label (tr "modals.update-remote-component.cancel")
:accept-label (tr "modals.update-remote-component.accept")
:accept-style :primary
:on-accept confirm-update-remote-component}))
do-show-component (st/emitf (dw/go-to-component selected-objects))
do-navigate-component-file (st/emitf (dwl/nav-to-component-file
(:component-file shape)))
do-transform-to-path (st/emitf (dw/convert-selected-to-path))
do-flatten (st/emitf (dw/convert-selected-to-path))]
(mf/defc context-menu-edit
[]
(let [do-copy (st/emitf (dw/copy-selected))
do-cut (st/emitf (dw/copy-selected) dw/delete-selected)
do-paste (st/emitf dw/paste)
do-duplicate (st/emitf (dw/duplicate-selected false))]
[:*
[:& menu-entry {:title (tr "workspace.shape.menu.copy")
:shortcut (sc/get-tooltip :copy)
@ -187,7 +104,16 @@
[:& menu-entry {:title (tr "workspace.shape.menu.duplicate")
:shortcut (sc/get-tooltip :duplicate)
:on-click do-duplicate}]
[:& menu-separator]
[:& menu-separator]]))
(mf/defc context-menu-layer-position
[]
(let [do-bring-forward (st/emitf (dw/vertical-order-selected :up))
do-bring-to-front (st/emitf (dw/vertical-order-selected :top))
do-send-backward (st/emitf (dw/vertical-order-selected :down))
do-send-to-back (st/emitf (dw/vertical-order-selected :bottom))]
[:*
[:& menu-entry {:title (tr "workspace.shape.menu.forward")
:shortcut (sc/get-tooltip :bring-forward)
:on-click do-bring-forward}]
@ -200,49 +126,100 @@
[:& menu-entry {:title (tr "workspace.shape.menu.back")
:shortcut (sc/get-tooltip :bring-back)
:on-click do-send-to-back}]
[:& menu-separator]
[:& menu-separator]]))
(mf/defc context-menu-flip
[]
(let [do-flip-vertical (st/emitf (dw/flip-vertical-selected))
do-flip-horizontal (st/emitf (dw/flip-horizontal-selected))]
[:*
[:& menu-entry {:title (tr "workspace.shape.menu.flip-vertical")
:shortcut (sc/get-tooltip :flip-vertical)
:on-click do-flip-vertical}]
[:& menu-entry {:title (tr "workspace.shape.menu.flip-horizontal")
:shortcut (sc/get-tooltip :flip-horizontal)
:on-click do-flip-horizontal}]
[:& menu-separator]
[:& menu-separator]]))
(when multiple?
[:*
[:& menu-entry {:title (tr "workspace.shape.menu.group")
:shortcut (sc/get-tooltip :group)
:on-click do-create-group}]
[:& menu-entry {:title (tr "workspace.shape.menu.mask")
:shortcut (sc/get-tooltip :mask)
:on-click do-mask-group}]])
(mf/defc context-menu-group
[{:keys [shapes]}]
(when (and single? (and (not has-mask-group?) (or has-bool? has-group?)))
(let [multiple? (> (count shapes) 1)
single? (= (count shapes) 1)
has-group? (->> shapes (d/seek #(= :group (:type %))))
has-bool? (->> shapes (d/seek #(= :bool (:type %))))
has-mask? (->> shapes (d/seek :masked-group?))
has-frame? (->> shapes (d/seek #(= :frame (:type %))))
is-group? (and single? has-group?)
is-bool? (and single? has-bool?)
do-create-group (st/emitf dw/group-selected)
do-mask-group (st/emitf dw/mask-group)
do-remove-group (st/emitf dw/ungroup-selected)
do-unmask-group (st/emitf dw/unmask-group)]
[:*
(when (or has-bool? has-group? has-mask?)
[:& menu-entry {:title (tr "workspace.shape.menu.ungroup")
:shortcut (sc/get-tooltip :ungroup)
:on-click do-remove-group}])
(when (not has-frame?)
[:& menu-entry {:title (tr "workspace.shape.menu.group")
:shortcut (sc/get-tooltip :group)
:on-click do-create-group}])
(when (or multiple? (and is-group? (not has-mask?)) is-bool?)
[:& menu-entry {:title (tr "workspace.shape.menu.mask")
:shortcut (sc/get-tooltip :mask)
:on-click do-mask-group}])
(when (or has-bool? has-group?)
[:& menu-entry {:title (tr "workspace.shape.menu.ungroup")
:shortcut (sc/get-tooltip :ungroup)
:on-click do-remove-group}])
(when has-mask-group?
[:& menu-entry {:title (tr "workspace.shape.menu.unmask")
:shortcut (sc/get-tooltip :unmask)
:on-click do-unmask-group}]
)
(when has-mask?
[:& menu-entry {:title (tr "workspace.shape.menu.unmask")
:shortcut (sc/get-tooltip :unmask)
:on-click do-unmask-group}])
(when (or multiple? has-mask-group? (or is-bool? has-group?) (and single? (or has-bool? has-group?)) )
[:& menu-separator])
(when (not has-frame?)
[:& menu-separator])]))
(when (and single? editable-shape?)
(mf/defc context-menu-path
[{:keys [shapes disable-flatten? disable-booleans?]}]
(let [multiple? (> (count shapes) 1)
single? (= (count shapes) 1)
has-group? (->> shapes (d/seek #(= :group (:type %))))
has-bool? (->> shapes (d/seek #(= :bool (:type %))))
has-frame? (->> shapes (d/seek #(= :frame (:type %))))
is-group? (and single? has-group?)
is-bool? (and single? has-bool?)
is-frame? (and single? has-frame?)
do-start-editing #(timers/schedule (st/emitf (dw/start-editing-selected)))
do-transform-to-path (st/emitf (dw/convert-selected-to-path))
make-do-bool
(fn [bool-type]
#(cond
multiple?
(st/emit! (dw/create-bool bool-type))
is-group?
(st/emit! (dw/group-to-bool (-> shapes first :id) bool-type))
is-bool?
(st/emit! (dw/change-bool-type (-> shapes first :id) bool-type))))]
[:*
(when (and single? (not is-frame?))
[:& menu-entry {:title (tr "workspace.shape.menu.edit")
:shortcut (sc/get-tooltip :start-editing)
:on-click do-start-editing}])
(when-not disable-flatten?
(when-not (or disable-flatten? has-frame?)
[:& menu-entry {:title (tr "workspace.shape.menu.transform-to-path")
:on-click do-transform-to-path}])
@ -251,84 +228,159 @@
[:& menu-entry {:title (tr "workspace.shape.menu.path")}
[:& menu-entry {:title (tr "workspace.shape.menu.union")
:shortcut (sc/get-tooltip :bool-union)
:on-click (set-bool :union)}]
:on-click (make-do-bool :union)}]
[:& menu-entry {:title (tr "workspace.shape.menu.difference")
:shortcut (sc/get-tooltip :bool-difference)
:on-click (set-bool :difference)}]
:on-click (make-do-bool :difference)}]
[:& menu-entry {:title (tr "workspace.shape.menu.intersection")
:shortcut (sc/get-tooltip :bool-intersection)
:on-click (set-bool :intersection)}]
:on-click (make-do-bool :intersection)}]
[:& menu-entry {:title (tr "workspace.shape.menu.exclude")
:shortcut (sc/get-tooltip :bool-exclude)
:on-click (set-bool :exclude)}]
:on-click (make-do-bool :exclude)}]
(when (and single? is-bool? (not disable-flatten?))
[:*
[:& menu-separator]
[:& menu-entry {:title (tr "workspace.shape.menu.flatten")
:on-click do-flatten}]])])
:on-click do-transform-to-path}]])])]))
(if (:hidden shape)
(mf/defc context-menu-layer-options
[{:keys [shapes]}]
(let [ids (mapv :id shapes)
do-show-shape (st/emitf (dw/update-shape-flags ids {:hidden false}))
do-hide-shape (st/emitf (dw/update-shape-flags ids {:hidden true}))
do-lock-shape (st/emitf (dw/update-shape-flags ids {:blocked true}))
do-unlock-shape (st/emitf (dw/update-shape-flags ids {:blocked false}))]
[:*
(if (every? :hidden shapes)
[:& menu-entry {:title (tr "workspace.shape.menu.show")
:on-click do-show-shape}]
[:& menu-entry {:title (tr "workspace.shape.menu.hide")
:on-click do-hide-shape}])
(if (:blocked shape)
(if (every? :blocked shapes)
[:& menu-entry {:title (tr "workspace.shape.menu.unlock")
:on-click do-unlock-shape}]
[:& menu-entry {:title (tr "workspace.shape.menu.lock")
:on-click do-lock-shape}])
:on-click do-lock-shape}])]))
(when (and (= options-mode :prototype) (= (:type shape) :frame))
(let [flow (cto/get-frame-flow flows (:id shape))]
(if (nil? flow)
[:& menu-entry {:title (tr "workspace.shape.menu.flow-start")
:on-click do-add-flow}]
[:& menu-entry {:title (tr "workspace.shape.menu.delete-flow-start")
:on-click (do-remove-flow flow)}])))
(mf/defc context-menu-prototype
[{:keys [shapes]}]
(let [options (mf/deref refs/workspace-page-options)
options-mode (mf/deref refs/options-mode)
do-add-flow (st/emitf (dwi/add-flow-selected-frame))
do-remove-flow #(st/emitf (dwi/remove-flow (:id %)))
flows (:flows options)
(when (and (not= (:type shape) :frame)
(or multiple? (nil? (:component-id shape))))
prototype? (= options-mode :prototype)
single? (= (count shapes) 1)
has-frame? (->> shapes (d/seek #(= :frame (:type %))))
is-frame? (and single? has-frame?)]
(when (and prototype? is-frame?)
(let [flow (cto/get-frame-flow flows (-> shapes first :id))]
(if (some? flow)
[:& menu-entry {:title (tr "workspace.shape.menu.delete-flow-start")
:on-click (do-remove-flow flow)}]
[:& menu-entry {:title (tr "workspace.shape.menu.flow-start")
:on-click do-add-flow}])))))
(mf/defc context-menu-component
[{:keys [shapes]}]
(let [single? (= (count shapes) 1)
has-frame? (->> shapes (d/seek #(= :frame (:type %))))
is-component? (and single? (-> shapes first :component-id some?))
shape-id (->> shapes first :id)
component-id (->> shapes first :component-id)
component-file (-> shapes first :component-file)
current-file-id (mf/use-ctx ctx/current-file-id)
local-component? (= component-file current-file-id)
do-add-component (st/emitf (dwl/add-component))
do-detach-component (st/emitf (dwl/detach-component shape-id))
do-reset-component (st/emitf (dwl/reset-component shape-id))
do-show-component (st/emitf (dw/go-to-component component-id))
do-navigate-component-file (st/emitf (dwl/nav-to-component-file component-file))
do-update-component (st/emitf (dwl/update-component-sync shape-id component-file))
do-update-remote-component
(st/emitf (modal/show
{:type :confirm
:message ""
:title (tr "modals.update-remote-component.message")
:hint (tr "modals.update-remote-component.hint")
:cancel-label (tr "modals.update-remote-component.cancel")
:accept-label (tr "modals.update-remote-component.accept")
:accept-style :primary
:on-accept do-update-component}))]
[:*
(when (and (not has-frame?) (not is-component?))
[:*
[:& menu-separator]
[:& menu-entry {:title (tr "workspace.shape.menu.create-component")
:shortcut (sc/get-tooltip :create-component)
:on-click do-add-component}]])
(when (and (:component-id shape)
(= (count selected) 1))
(when is-component?
;; WARNING: this menu is the same as the context menu at the sidebar.
;; If you change it, you must change equally the file
;; app/main/ui/workspace/sidebar/options/component.cljs
(if (= (:component-file shape) current-file-id)
[:*
[:& menu-separator]
[:& menu-entry {:title (tr "workspace.shape.menu.detach-instance")
:shortcut (sc/get-tooltip :detach-component)
:on-click do-detach-component}]
[:& menu-entry {:title (tr "workspace.shape.menu.reset-overrides")
:on-click do-reset-component}]
[:& menu-entry {:title (tr "workspace.shape.menu.update-main")
:on-click do-update-component}]
[:& menu-entry {:title (tr "workspace.shape.menu.show-main")
:on-click do-show-component}]]
[:*
[:& menu-separator]
[:& menu-entry {:title (tr "workspace.shape.menu.detach-instance")
:shortcut (sc/get-tooltip :detach-component)
:on-click do-detach-component}]
[:& menu-entry {:title (tr "workspace.shape.menu.reset-overrides")
:on-click do-reset-component}]
[:& menu-entry {:title (tr "workspace.shape.menu.go-main")
:on-click do-navigate-component-file}]
[:& menu-entry {:title (tr "workspace.shape.menu.update-main")
:on-click do-update-remote-component}]]))
;; app/main/ui/workspace/sidebar/options/menus/component.cljs
[:& menu-separator]
[:& menu-entry {:title (tr "workspace.shape.menu.delete")
:shortcut (sc/get-tooltip :delete)
:on-click do-delete}]]))
[:*
[:& menu-separator]
[:& menu-entry {:title (tr "workspace.shape.menu.detach-instance")
:shortcut (sc/get-tooltip :detach-component)
:on-click do-detach-component}]
[:& menu-entry {:title (tr "workspace.shape.menu.reset-overrides")
:on-click do-reset-component}]
(if local-component?
[:*
[:& menu-entry {:title (tr "workspace.shape.menu.update-main")
:on-click do-update-component}]
[:& menu-entry {:title (tr "workspace.shape.menu.show-main")
:on-click do-show-component}]]
[:*
[:& menu-entry {:title (tr "workspace.shape.menu.go-main")
:on-click do-navigate-component-file}]
[:& menu-entry {:title (tr "workspace.shape.menu.update-main")
:on-click do-update-remote-component}]])])
[:& menu-separator]]))
(mf/defc context-menu-delete
[]
(let [do-delete (st/emitf dw/delete-selected)]
[:& menu-entry {:title (tr "workspace.shape.menu.delete")
:shortcut (sc/get-tooltip :delete)
:on-click do-delete}]))
(mf/defc shape-context-menu
[{:keys [mdata] :as props}]
(let [{:keys [disable-booleans? disable-flatten?]} mdata
shapes (mf/deref refs/selected-objects)
props #js {:shapes shapes
:disable-booleans? disable-booleans?
:disable-flatten? disable-flatten?}]
(when-not (empty? shapes)
[:*
[:> context-menu-edit props]
[:> context-menu-layer-position props]
[:> context-menu-flip props]
[:> context-menu-group props]
[:> context-menu-path props]
[:> context-menu-layer-options props]
[:> context-menu-prototype props]
[:> context-menu-component props]
[:> context-menu-delete props]])))
(mf/defc viewport-context-menu
[]
@ -364,7 +416,7 @@
:style {:top top :left left}
:on-context-menu prevent-default}
(if (:shape mdata)
(if (contains? mdata :selected)
[:& shape-context-menu {:mdata mdata}]
[:& viewport-context-menu {:mdata mdata}])]]))

View file

@ -139,16 +139,16 @@
(fn [event]
(dom/stop-propagation event)
(if (:blocked item)
(st/emit! (dw/update-shape-flags id {:blocked false}))
(st/emit! (dw/update-shape-flags id {:blocked true})
(st/emit! (dw/update-shape-flags [id] {:blocked false}))
(st/emit! (dw/update-shape-flags [id] {:blocked true})
(dw/deselect-shape id))))
toggle-visibility
(fn [event]
(dom/stop-propagation event)
(if (:hidden item)
(st/emit! (dw/update-shape-flags id {:hidden false}))
(st/emit! (dw/update-shape-flags id {:hidden true}))))
(st/emit! (dw/update-shape-flags [id] {:hidden false}))
(st/emit! (dw/update-shape-flags [id] {:hidden true}))))
select-shape
(fn [event]
@ -275,7 +275,7 @@
[:ul.element-list
[:& hooks/sortable-container {}
(for [[index id] (reverse (d/enumerate (:shapes root)))]
(let [obj (get objects id)]
(when-let [obj (get objects id)]
(if (= (:type obj) :frame)
[:& frame-wrapper
{:item obj

View file

@ -10,7 +10,6 @@
[app.main.data.modal :as modal]
[app.main.data.workspace :as dw]
[app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.undo :as dwu]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.context-menu :refer [context-menu]]
@ -33,10 +32,9 @@
show? (some? (:component-id values))
local-library (mf/deref refs/workspace-local-library)
libraries (mf/deref refs/workspace-libraries)
component (cp/get-component (:component-id values)
(:component-file values)
local-library
libraries)
{:keys [component-id component-file]} values
component (cp/get-component component-id component-file local-library libraries)
on-menu-click (mf/use-callback
(fn [event]
@ -49,29 +47,21 @@
do-detach-component (st/emitf (dwl/detach-component id))
do-reset-component (st/emitf (dwl/reset-component id))
do-update-component (st/emitf
(dwu/start-undo-transaction)
(dwl/update-component id)
(dwl/sync-file current-file-id current-file-id)
(dwu/commit-undo-transaction))
confirm-update-remote-component (st/emitf
(dwl/update-component id)
(dwl/sync-file current-file-id
(:component-file values))
(dwl/sync-file (:component-file values)
(:component-file values)))
do-update-remote-component (st/emitf (modal/show
{:type :confirm
:message ""
:title (t locale "modals.update-remote-component.message")
:hint (t locale "modals.update-remote-component.hint")
:cancel-label (t locale "modals.update-remote-component.cancel")
:accept-label (t locale "modals.update-remote-component.accept")
:accept-style :primary
:on-accept confirm-update-remote-component}))
do-show-component (st/emitf (dw/go-to-layout :assets))
do-navigate-component-file (st/emitf (dwl/nav-to-component-file
(:component-file values)))]
do-update-component (st/emitf (dwl/update-component-sync id component-file))
do-update-remote-component
(st/emitf (modal/show
{:type :confirm
:message ""
:title (t locale "modals.update-remote-component.message")
:hint (t locale "modals.update-remote-component.hint")
:cancel-label (t locale "modals.update-remote-component.cancel")
:accept-label (t locale "modals.update-remote-component.accept")
:accept-style :primary
:on-accept do-update-component}))
do-show-component (st/emitf (dw/go-to-component component-id))
do-navigate-component-file (st/emitf (dwl/nav-to-component-file component-file))]
(when show?
[:div.element-set
[:div.element-set-title

View file

@ -30,24 +30,18 @@
:name (:name shape)
:exports exports}))
(mf/defc exports-menu
[{:keys [shape page-id file-id] :as props}]
(let [exports (:exports shape [])
loading? (mf/use-state false)
(defn use-download-export
[shape page-id file-id exports]
(let [loading? (mf/use-state false)
filename (cond-> (:name shape)
(and (= (count exports) 1)
(not (empty (:suffix (first exports)))))
(str (:suffix (first exports))))
scale-enabled?
on-download-callback
(mf/use-callback
(fn [export]
(#{:png :jpeg} (:type export))))
on-download
(mf/use-callback
(mf/deps shape)
(mf/deps filename shape exports)
(fn [event]
(dom/prevent-default event)
(swap! loading? not)
@ -59,7 +53,19 @@
(swap! loading? not)
(st/emit! (dm/error (tr "errors.unexpected-error"))))
(fn []
(swap! loading? not))))))
(swap! loading? not))))))]
[on-download-callback @loading?]))
(mf/defc exports-menu
[{:keys [shape page-id file-id] :as props}]
(let [exports (:exports shape [])
scale-enabled?
(mf/use-callback
(fn [export]
(#{:png :jpeg} (:type export))))
[on-download loading?] (use-download-export shape page-id file-id exports)
add-export
(mf/use-callback
@ -143,11 +149,11 @@
i/minus]])
[:div.btn-icon-dark.download-button
{:on-click (when-not @loading? on-download)
{:on-click (when-not loading? on-download)
:class (dom/classnames
:btn-disabled @loading?)
:disabled @loading?}
(if @loading?
:btn-disabled loading?)
:disabled loading?}
(if loading?
(tr "workspace.options.exporting-object")
(tr "workspace.options.export-object"))]])]))

View file

@ -119,6 +119,7 @@
on-pointer-move (actions/on-pointer-move viewport-ref zoom move-stream)
on-pointer-up (actions/on-pointer-up)
on-move-selected (actions/on-move-selected hover hover-ids selected)
on-menu-selected (actions/on-menu-selected hover hover-ids selected)
on-frame-enter (actions/on-frame-enter frame-hover)
on-frame-leave (actions/on-frame-leave frame-hover)
@ -241,7 +242,8 @@
:zoom zoom
:edition edition
:disable-handlers (or drawing-tool edition)
:on-move-selected on-move-selected}])
:on-move-selected on-move-selected
:on-context-menu on-menu-selected}])
(when show-measures?
[:& msr/measurement

View file

@ -203,6 +203,16 @@
:shape @hover})
(dw/show-context-menu {:position position})))))))))
(defn on-menu-selected
[hover hover-ids selected]
(mf/use-callback
(mf/deps @hover hover-ids selected)
(fn [event]
(dom/prevent-default event)
(dom/stop-propagation event)
(let [position (dom/get-client-position event)]
(st/emit! (dw/show-shape-context-menu {:position position}))))))
(defn on-mouse-up
[disable-paste]
(mf/use-callback

View file

@ -33,7 +33,7 @@
(def min-selrect-side 10)
(def small-selrect-side 30)
(mf/defc selection-rect [{:keys [transform rect zoom color on-move-selected]}]
(mf/defc selection-rect [{:keys [transform rect zoom color on-move-selected on-context-menu]}]
(when rect
(let [{:keys [x y width height]} rect]
[:rect.main.viewport-selrect
@ -43,6 +43,7 @@
:height height
:transform transform
:on-mouse-down on-move-selected
:on-context-menu on-context-menu
:style {:stroke color
:stroke-width (/ selection-rect-width zoom)
:fill "none"}}])))
@ -223,6 +224,7 @@
zoom (obj/get props "zoom")
color (obj/get props "color")
on-move-selected (obj/get props "on-move-selected")
on-context-menu (obj/get props "on-context-menu")
on-resize (obj/get props "on-resize")
on-rotate (obj/get props "on-rotate")
disable-handlers (obj/get props "disable-handlers")
@ -244,7 +246,8 @@
:transform transform
:zoom zoom
:color color
:on-move-selected on-move-selected}]
:on-move-selected on-move-selected
:on-context-menu on-context-menu}]
;; Handlers
(for [{:keys [type position props]} (handlers-for-selection selrect shape zoom)]
@ -281,7 +284,7 @@
:fill "none"}}]]))
(mf/defc multiple-selection-handlers
[{:keys [shapes selected zoom color disable-handlers on-move-selected] :as props}]
[{:keys [shapes selected zoom color disable-handlers on-move-selected on-context-menu] :as props}]
(let [shape (mf/use-memo
(mf/deps shapes)
#(->> shapes
@ -310,13 +313,14 @@
:disable-handlers disable-handlers
:on-move-selected on-move-selected
:on-resize on-resize
:on-rotate on-rotate}]
:on-rotate on-rotate
:on-context-menu on-context-menu}]
(when (debug? :selection-center)
[:circle {:cx (:x shape-center) :cy (:y shape-center) :r 5 :fill "yellow"}])]))
(mf/defc single-selection-handlers
[{:keys [shape zoom color disable-handlers on-move-selected] :as props}]
[{:keys [shape zoom color disable-handlers on-move-selected on-context-menu] :as props}]
(let [shape-id (:id shape)
shape (geom/transform-shape shape {:round-coords? false})
@ -342,11 +346,12 @@
:on-rotate on-rotate
:on-resize on-resize
:disable-handlers disable-handlers
:on-move-selected on-move-selected}]))
:on-move-selected on-move-selected
:on-context-menu on-context-menu}]))
(mf/defc selection-handlers
{::mf/wrap [mf/memo]}
[{:keys [shapes selected edition zoom disable-handlers on-move-selected] :as props}]
[{:keys [shapes selected edition zoom disable-handlers on-move-selected on-context-menu] :as props}]
(let [num (count shapes)
{:keys [type] :as shape} (first shapes)
@ -363,7 +368,8 @@
:zoom zoom
:color color
:disable-handlers disable-handlers
:on-move-selected on-move-selected}]
:on-move-selected on-move-selected
:on-context-menu on-context-menu}]
(and (= type :text)
(= edition (:id shape)))
@ -380,4 +386,5 @@
:zoom zoom
:color color
:disable-handlers disable-handlers
:on-move-selected on-move-selected}])))
:on-move-selected on-move-selected
:on-context-menu on-context-menu}])))

View file

@ -72,7 +72,7 @@
[shape-node])))
(defn update-transform [shapes transforms modifiers]
(doseq [{id :id :as shape} shapes]
(doseq [{:keys [id type] :as shape} shapes]
(when-let [nodes (get-nodes shape)]
(let [transform (get transforms id)
modifiers (get-in modifiers [id :modifiers])

View file

@ -304,7 +304,7 @@
[content points]
(let [segments-set (into #{}
(juxt :start :end)
(map (juxt :start :end))
(get-segments content points))
create-line-command (fn [point other]