mirror of
https://github.com/penpot/penpot.git
synced 2025-01-10 08:50:57 -05:00
Merge pull request #238 from uxbox/393/hover_feedback
Hover feedback on shapes
This commit is contained in:
commit
8989591b04
7 changed files with 110 additions and 14 deletions
|
@ -297,3 +297,11 @@
|
|||
|
||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})
|
||||
(select-shapes selected))))))
|
||||
|
||||
(defn change-hover-state [id value]
|
||||
(ptk/reify ::change-hover-state
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update-in [:workspace-local :hover] #(if (nil? %) #{} %))
|
||||
(update-in [:workspace-local :hover] (comp (if value conj disj)) id)))))
|
||||
|
|
|
@ -147,6 +147,9 @@
|
|||
(def vbox
|
||||
(l/derived :vbox workspace-local))
|
||||
|
||||
(def current-hover
|
||||
(l/derived :hover workspace-local))
|
||||
|
||||
;; ---- Viewer refs
|
||||
|
||||
(def viewer-data
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
(mf/fnc frame-shape
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(let [childs (unchecked-get props "childs")
|
||||
(let [children (unchecked-get props "children")
|
||||
shape (unchecked-get props "shape")
|
||||
{:keys [id x y width height]} shape
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
|||
:height height}))]
|
||||
[:svg {:x x :y y :width width :height height}
|
||||
[:> "rect" props]
|
||||
(for [[i item] (d/enumerate childs)]
|
||||
(for [[i item] (d/enumerate children)]
|
||||
[:& shape-wrapper {:frame shape
|
||||
:shape item
|
||||
:key (:id item)}])])))
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
[uxbox.main.ui.shapes.circle :as circle]
|
||||
[uxbox.main.ui.shapes.icon :as icon]
|
||||
[uxbox.main.ui.shapes.image :as image]
|
||||
[uxbox.main.data.workspace.selection :as dws]
|
||||
[uxbox.main.store :as st]
|
||||
|
||||
;; Shapes that has some peculiarities are defined in its own
|
||||
;; namespace under uxbox.ui.workspace.shapes.* prefix, all the
|
||||
|
@ -52,20 +54,39 @@
|
|||
(and (identical? n-shape o-shape)
|
||||
(identical? n-frame o-frame)))))
|
||||
|
||||
(defn use-mouse-over
|
||||
[{:keys [id] :as shape}]
|
||||
(mf/use-callback
|
||||
(mf/deps shape)
|
||||
(fn []
|
||||
(st/emit! (dws/change-hover-state id true)))))
|
||||
|
||||
(defn use-mouse-out
|
||||
[{:keys [id] :as shape}]
|
||||
(mf/use-callback
|
||||
(mf/deps shape)
|
||||
(fn []
|
||||
(st/emit! (dws/change-hover-state id false)))))
|
||||
|
||||
(mf/defc shape-wrapper
|
||||
{::mf/wrap [#(mf/memo' % shape-wrapper-memo-equals?)]
|
||||
::mf/wrap-props false}
|
||||
[props]
|
||||
(let [shape (unchecked-get props "shape")
|
||||
frame (unchecked-get props "frame")
|
||||
opts #js {:shape (->> shape (geom/transform-shape frame))
|
||||
shape (geom/transform-shape frame shape)
|
||||
opts #js {:shape shape
|
||||
:frame frame}
|
||||
alt? (mf/use-state false)]
|
||||
alt? (mf/use-state false)
|
||||
on-mouse-over (use-mouse-over shape)
|
||||
on-mouse-out (use-mouse-out shape)]
|
||||
|
||||
(hooks/use-stream ms/keyboard-alt #(reset! alt? %))
|
||||
|
||||
(when (and shape (not (:hidden shape)))
|
||||
[:g.shape {:style {:cursor (if @alt? cur/duplicate nil)}}
|
||||
[:g.shape-wrapper {:on-mouse-over on-mouse-over
|
||||
:on-mouse-out on-mouse-out
|
||||
:style {:cursor (if @alt? cur/duplicate nil)}}
|
||||
(case (:type shape)
|
||||
:curve [:> path/path-wrapper opts]
|
||||
:path [:> path/path-wrapper opts]
|
||||
|
@ -79,7 +100,7 @@
|
|||
;; Only used when drawing a new frame.
|
||||
:frame [:> frame-wrapper {:shape shape}]
|
||||
nil)
|
||||
[:& bounding-box {:shape (->> shape (geom/transform-shape frame)) :frame frame}]])))
|
||||
[:& bounding-box {:shape shape :frame frame}]])))
|
||||
|
||||
(def group-wrapper (group/group-wrapper-factory shape-wrapper))
|
||||
(def frame-wrapper (frame/frame-wrapper-factory shape-wrapper))
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
(ns uxbox.main.ui.workspace.shapes.frame
|
||||
(:require
|
||||
[clojure.set :as set]
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.main.constants :as c]
|
||||
|
@ -16,6 +17,7 @@
|
|||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.workspace.shapes.common :as common]
|
||||
[uxbox.main.ui.workspace.shapes.outline :refer [outline]]
|
||||
[uxbox.main.ui.shapes.frame :as frame]
|
||||
[uxbox.common.geom.matrix :as gmt]
|
||||
[uxbox.common.geom.point :as gpt]
|
||||
|
@ -58,6 +60,9 @@
|
|||
selected? (mf/deref selected-iref)
|
||||
zoom (mf/deref refs/selected-zoom)
|
||||
|
||||
selected-shape? (or (mf/deref refs/selected-shapes) #{})
|
||||
hover? (or (mf/deref refs/current-hover) #{})
|
||||
outline? (set/union selected-shape? hover?)
|
||||
|
||||
on-mouse-down (mf/use-callback (mf/deps shape)
|
||||
#(common/on-mouse-down % shape))
|
||||
|
@ -68,7 +73,7 @@
|
|||
{:keys [x y width height]} shape
|
||||
|
||||
inv-zoom (/ 1 zoom)
|
||||
childs (mapv #(get objects %) (:shapes shape))
|
||||
children (mapv #(get objects %) (:shapes shape))
|
||||
ds-modifier (get-in shape [:modifiers :displacement])
|
||||
|
||||
label-pos (gpt/point x (- y (/ 10 zoom)))
|
||||
|
@ -102,7 +107,12 @@
|
|||
;; User may also select the frame with single click in the label
|
||||
:on-click on-double-click}
|
||||
(:name shape)]
|
||||
[:& frame-shape
|
||||
{:shape shape
|
||||
:childs childs}]])))))
|
||||
[:*
|
||||
[:& frame-shape
|
||||
{:shape shape
|
||||
:children children}]
|
||||
|
||||
[:g.outlines
|
||||
(for [child (filter (comp outline? :id) children)]
|
||||
[:& outline {:shape (geom/transform-shape child)}])]]])))))
|
||||
|
||||
|
|
52
frontend/src/uxbox/main/ui/workspace/shapes/outline.cljs
Normal file
52
frontend/src/uxbox/main/ui/workspace/shapes/outline.cljs
Normal file
|
@ -0,0 +1,52 @@
|
|||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2020 UXBOX Labs SL
|
||||
|
||||
(ns uxbox.main.ui.workspace.shapes.outline
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.common.geom.shapes :as gsh]
|
||||
[uxbox.util.object :as obj]
|
||||
[rumext.util :refer [map->obj]]
|
||||
[uxbox.main.ui.shapes.path :as path]))
|
||||
|
||||
|
||||
(mf/defc outline
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(let [shape (unchecked-get props "shape")
|
||||
transform (gsh/transform-matrix shape)
|
||||
{:keys [id x y width height]} shape
|
||||
|
||||
outline-type (case (:type shape)
|
||||
:circle "ellipse"
|
||||
(:curve :path) "path"
|
||||
"rect")
|
||||
|
||||
common {:fill "transparent"
|
||||
:stroke "#31EFB8"
|
||||
:stroke-width "1px"
|
||||
:pointer-events "none"
|
||||
:transform transform}
|
||||
|
||||
props (case (:type shape)
|
||||
:circle
|
||||
{:cx (+ x (/ width 2))
|
||||
:cy (+ y (/ height 2))
|
||||
:rx (/ width 2)
|
||||
:ry (/ height 2)}
|
||||
|
||||
(:curve :path)
|
||||
{:d (path/render-path shape)}
|
||||
|
||||
{:x x
|
||||
:y y
|
||||
:width width
|
||||
:height height})]
|
||||
|
||||
[:> outline-type (map->obj (merge common props))]))
|
|
@ -27,8 +27,7 @@
|
|||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(let [shape (unchecked-get props "shape")
|
||||
selected (mf/deref refs/selected-shapes)
|
||||
selected? (contains? selected (:id shape))
|
||||
hover? (or (mf/deref refs/current-hover) #{})
|
||||
on-mouse-down (mf/use-callback
|
||||
(mf/deps shape)
|
||||
#(common/on-mouse-down % shape))
|
||||
|
@ -38,8 +37,11 @@
|
|||
on-double-click (mf/use-callback
|
||||
(mf/deps shape)
|
||||
(fn [event]
|
||||
(when selected?
|
||||
(st/emit! (dw/start-edition-mode (:id shape))))))]
|
||||
(when (hover? (:id shape))
|
||||
(do
|
||||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event)
|
||||
(st/emit! (dw/start-edition-mode (:id shape)))))))]
|
||||
|
||||
[:g.shape {:on-double-click on-double-click
|
||||
:on-mouse-down on-mouse-down
|
||||
|
|
Loading…
Reference in a new issue