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

Merge pull request #636 from penpot/feature/other-improvements

Deep selection improvements
This commit is contained in:
Andrés Moya 2021-02-15 12:52:14 +01:00 committed by GitHub
commit 23f95c2b2b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 319 additions and 146 deletions

View file

@ -5,7 +5,8 @@
### New features
- Bounce & Complaint handling.
- Disable groups interactions when holding "Ctrl" key (deep selection)
- New action in context menu to "edit" some shapes (binded to key "Enter")
### Bugs fixed

View file

@ -1,3 +1,12 @@
;; 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-2021 UXBOX Labs SL
(ns app.browser
(:require
[lambdaisland.glogi :as log]

View file

@ -1,3 +1,12 @@
;; 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-2021 UXBOX Labs SL
(ns app.config
(:require
["process" :as process]

View file

@ -1,3 +1,12 @@
;; 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-2021 UXBOX Labs SL
(ns app.core
(:require
[lambdaisland.glogi :as log]

View file

@ -1,3 +1,12 @@
;; 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-2021 UXBOX Labs SL
(ns app.http
(:require
[app.http.export :refer [export-handler]]

View file

@ -1,3 +1,12 @@
;; 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-2021 UXBOX Labs SL
(ns app.http.export-bitmap
(:require
[cuerdas.core :as str]

View file

@ -1,3 +1,12 @@
;; 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-2021 UXBOX Labs SL
(ns app.http.export-svg
(:require
[cuerdas.core :as str]

View file

@ -1,3 +1,12 @@
;; 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-2021 UXBOX Labs SL
(ns app.http.impl
(:require
["http" :as http]

View file

@ -5,7 +5,7 @@
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
;; Copyright (c) 2020 app Labs SL
;; Copyright (c) 2020-2021 UXBOX Labs SL
(ns app.util.transit
(:require

View file

@ -1,3 +1,12 @@
;; 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-2021 UXBOX Labs SL
(ns app.zipfile
(:require
["jszip" :as jszip]))

View file

@ -4841,5 +4841,11 @@
"en" : "Flip vertical",
"es" : "Voltear vertical"
}
},
"workspace.shape.menu.edit" : {
"translations" : {
"en" : "Edit",
"es" : "Editar"
}
}
}

View file

@ -24,6 +24,7 @@
(def mac-shift "\u21E7")
(def mac-control "\u2303")
(def mac-esc "\u238B")
(def mac-enter "\u23CE")
(def left-arrow "\u2190")
(def up-arrow "\u2191")
@ -73,3 +74,7 @@
mac-esc
"Escape"))
(defn enter []
(if (cfg/check-platform? :macos)
mac-enter
"Enter"))

View file

@ -1089,6 +1089,31 @@
(rx/of (relocate-shapes selected parent-id to-index))))))
(defn start-editing-selected
[]
(ptk/reify ::start-editing-selected
ptk/WatchEvent
(watch [_ state stream]
(let [selected (get-in state [:workspace-local :selected])]
(if-not (= 1 (count selected))
(rx/empty)
(let [objects (dwc/lookup-page-objects state)
{:keys [id type shapes]} (get objects (first selected))]
(case type
:text
(rx/of (dwc/start-edition-mode id))
:group
(rx/of (dwc/select-shapes (into (d/ordered-set) [(last shapes)])))
:path
(rx/of (dwc/start-edition-mode id)
(dwdp/start-path-edit id))
:else (rx/empty))))))))
;; --- Change Page Order (D&D Ordering)
(defn relocate-page

View file

@ -255,7 +255,12 @@
:escape {:tooltip (ds/esc)
:command "escape"
:fn #(st/emit! (esc-pressed))}})
:fn #(st/emit! (esc-pressed))}
:start-editing {:tooltip (ds/enter)
:command "enter"
:fn #(st/emit! (dw/start-editing-selected))}
})
(defn get-tooltip [shortcut]
(assert (contains? shortcuts shortcut) (str shortcut))

View file

@ -11,11 +11,12 @@
[app.main.store :as st]
[app.main.refs :as refs]
[app.common.geom.point :as gpt]
[app.util.globals :as globals]))
[app.util.globals :as globals])
(:import goog.events.KeyCodes))
;; --- User Events
(defrecord KeyboardEvent [type key shift ctrl alt])
(defrecord KeyboardEvent [type key shift ctrl alt meta])
(defn keyboard-event?
[v]
@ -112,7 +113,28 @@
ob (->> (rx/merge
(->> st/stream
(rx/filter keyboard-event?)
(rx/map :alt))
(rx/filter #(let [key (:key %)]
(= key KeyCodes.ALT)))
(rx/map #(= :down (:type %))))
;; Fix a situation caused by using `ctrl+alt` kind of shortcuts,
;; that makes keyboard-alt stream registring the key pressed but
;; on bluring the window (unfocus) the key down is never arrived.
(->> window-blur
(rx/map (constantly false))))
(rx/dedupe))]
(rx/subscribe-with ob sub)
sub))
(defonce keyboard-ctrl
(let [sub (rx/behavior-subject nil)
ob (->> (rx/merge
(->> st/stream
(rx/filter keyboard-event?)
(rx/filter #(let [key (:key %)]
(or
(= key KeyCodes.CTRL)
(= key KeyCodes.META))))
(rx/map #(= :down (:type %))))
;; Fix a situation caused by using `ctrl+alt` kind of shortcuts,
;; that makes keyboard-alt stream registring the key pressed but
;; on bluring the window (unfocus) the key down is never arrived.

View file

@ -11,18 +11,18 @@
(:require
[app.config :as cfg]
[app.main.data.comments :as dcm]
[app.main.data.modal :as modal]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.streams :as ms]
[app.main.ui.context :as ctx]
[app.main.ui.components.dropdown :refer [dropdown]]
[app.main.data.modal :as modal]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.util.time :as dt]
[app.util.dom :as dom]
[app.util.object :as obj]
[app.util.i18n :as i18n :refer [t tr]]
[app.util.keyboard :as kbd]
[app.util.object :as obj]
[app.util.time :as dt]
[cuerdas.core :as str]
[okulary.core :as l]
[rumext.alpha :as mf]))

View file

@ -9,12 +9,12 @@
(ns app.main.ui.components.editable-label
(:require
[rumext.alpha :as mf]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.util.data :refer [classnames]]
[app.util.dom :as dom]
[app.util.keyboard :as kbd]
[app.util.timers :as timers]
[app.util.data :refer [classnames]]))
[rumext.alpha :as mf]))
(mf/defc editable-label
[{:keys [value on-change on-cancel editing? disable-dbl-click? class-name]}]

View file

@ -9,12 +9,12 @@
(ns app.main.ui.components.numeric-input
(:require
[rumext.alpha :as mf]
[app.main.ui.keyboard :as kbd]
[app.common.data :as d]
[app.common.math :as math]
[app.util.dom :as dom]
[app.util.keyboard :as kbd]
[app.util.object :as obj]
[app.common.math :as math]))
[rumext.alpha :as mf]))
(mf/defc numeric-input
{::mf/wrap-props false

View file

@ -8,17 +8,17 @@
;; Copyright (c) 2020 UXBOX Labs SL
(ns app.main.ui.confirm
(:import goog.events.EventType)
(:require
[rumext.alpha :as mf]
[goog.events :as events]
[app.main.data.modal :as modal]
[app.main.store :as st]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as k]
[app.util.data :refer [classnames]]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr t]]
[app.util.data :refer [classnames]]))
[app.util.keyboard :as k]
[goog.events :as events]
[rumext.alpha :as mf])
(:import goog.events.EventType))
(mf/defc confirm-dialog
{::mf/register modal/components

View file

@ -16,9 +16,9 @@
[app.main.ui.dashboard.grid :refer [grid]]
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [t]]
[app.util.keyboard :as kbd]
[app.util.router :as rt]
[okulary.core :as l]
[rumext.alpha :as mf]))

View file

@ -9,20 +9,20 @@
(ns app.main.ui.dashboard.grid
(:require
[app.common.uuid :as uuid]
[app.common.math :as mth]
[app.common.uuid :as uuid]
[app.config :as cfg]
[app.main.data.dashboard :as dd]
[app.main.data.modal :as modal]
[app.main.fonts :as fonts]
[app.main.store :as st]
[app.main.ui.components.context-menu :refer [context-menu]]
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.main.data.modal :as modal]
[app.main.worker :as wrk]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [t tr]]
[app.util.keyboard :as kbd]
[app.util.router :as rt]
[app.util.time :as dt]
[app.util.timers :as ts]

View file

@ -10,8 +10,8 @@
(ns app.main.ui.dashboard.inline-edition
(:require
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.util.dom :as dom]
[app.util.keyboard :as kbd]
[rumext.alpha :as mf]))
(mf/defc inline-edition

View file

@ -16,9 +16,9 @@
[app.main.store :as st]
[app.main.ui.dashboard.grid :refer [line-grid]]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [t tr]]
[app.util.keyboard :as kbd]
[app.util.router :as rt]
[app.util.time :as dt]
[okulary.core :as l]

View file

@ -13,10 +13,10 @@
[app.common.spec :as us]
[app.config :as cfg]
[app.main.data.auth :as da]
[app.main.data.comments :as dcm]
[app.main.data.dashboard :as dd]
[app.main.data.messages :as dm]
[app.main.data.modal :as modal]
[app.main.data.comments :as dcm]
[app.main.refs :as refs]
[app.main.repo :as rp]
[app.main.store :as st]
@ -26,13 +26,13 @@
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
[app.main.ui.dashboard.team-form]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.util.avatars :as avatars]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [t tr]]
[app.util.keyboard :as kbd]
[app.util.object :as obj]
[app.util.router :as rt]
[app.util.time :as dt]
[app.util.avatars :as avatars]
[beicon.core :as rx]
[cljs.spec.alpha :as s]
[cuerdas.core :as str]

View file

@ -20,10 +20,10 @@
[app.main.store :as st]
[app.main.ui.components.forms :refer [input submit-button form]]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.util.dom :as dom]
[app.util.forms :as fm]
[app.util.i18n :as i18n :refer [t tr]]
[app.util.keyboard :as kbd]
[app.util.object :as obj]
[app.util.router :as rt]
[app.util.time :as dt]

View file

@ -20,11 +20,11 @@
[app.main.ui.handoff.right-sidebar :refer [right-sidebar]]
[app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.main.ui.viewer.header :refer [header]]
[app.main.ui.viewer.thumbnails :refer [thumbnails-panel]]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [t tr]]
[app.util.keyboard :as kbd]
[beicon.core :as rx]
[goog.events :as events]
[okulary.core :as l]

View file

@ -14,10 +14,9 @@
[app.main.data.viewer :as dv]
[app.main.store :as st]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.main.ui.keyboard :as kbd]
[app.main.ui.workspace.sidebar.layers :refer [element-icon layer-name frame-wrapper]]
[app.util.dom :as dom]
[app.util.keyboard :as kbd]
[okulary.core :as l]
[rumext.alpha :as mf]))

View file

@ -9,14 +9,14 @@
(ns app.main.ui.modal
(:require
[okulary.core :as l]
[goog.events :as events]
[rumext.alpha :as mf]
[app.main.store :as st]
[app.main.ui.keyboard :as k]
[app.main.data.modal :as dm]
[app.main.refs :as refs]
[app.main.store :as st]
[app.util.dom :as dom]
[app.main.refs :as refs])
[app.util.keyboard :as k]
[goog.events :as events]
[okulary.core :as l]
[rumext.alpha :as mf])
(:import goog.events.EventType))
(defn- on-esc-clicked

View file

@ -15,21 +15,21 @@
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as geom]
[app.common.pages :as cp]
[app.main.data.comments :as dcm]
[app.main.data.viewer :as dv]
[app.main.data.viewer.shortcuts :as sc]
[app.main.data.comments :as dcm]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.comments :as cmt]
[app.main.ui.components.fullscreen :as fs]
[app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.main.ui.viewer.header :refer [header]]
[app.main.ui.viewer.shapes :as shapes :refer [frame-svg]]
[app.main.ui.viewer.thumbnails :refer [thumbnails-panel]]
[app.main.ui.comments :as cmt]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [t tr]]
[app.util.keyboard :as kbd]
[goog.events :as events]
[okulary.core :as l]
[rumext.alpha :as mf]))

View file

@ -21,7 +21,6 @@
[app.main.ui.context :as ctx]
[app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.main.ui.workspace.colorpalette :refer [colorpalette]]
[app.main.ui.workspace.colorpicker]
[app.main.ui.workspace.context-menu :refer [context-menu]]
@ -32,6 +31,7 @@
[app.main.ui.workspace.sidebar :refer [left-sidebar right-sidebar]]
[app.main.ui.workspace.viewport :refer [viewport viewport-actions coordinates]]
[app.util.dom :as dom]
[app.util.keyboard :as kbd]
[app.util.object :as obj]
[beicon.core :as rx]
[cuerdas.core :as str]

View file

@ -18,10 +18,10 @@
[app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.util.color :as uc]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [t]]
[app.util.keyboard :as kbd]
[app.util.object :as obj]
[beicon.core :as rx]
[cuerdas.core :as str]

View file

@ -9,16 +9,7 @@
(ns app.main.ui.workspace.colorpicker.pixel-overlay
(:require
[rumext.alpha :as mf]
[cuerdas.core :as str]
[okulary.core :as l]
[promesa.core :as p]
[beicon.core :as rx]
[goog.events :as events]
[app.common.uuid :as uuid]
[app.util.timers :as timers]
[app.util.dom :as dom]
[app.util.object :as obj]
[app.main.data.colors :as dwc]
[app.main.data.fetch :as mdf]
[app.main.data.modal :as modal]
@ -26,8 +17,17 @@
[app.main.store :as st]
[app.main.ui.context :as muc]
[app.main.ui.cursors :as cur]
[app.main.ui.keyboard :as kbd]
[app.main.ui.workspace.shapes :refer [shape-wrapper frame-wrapper]])
[app.main.ui.workspace.shapes :refer [shape-wrapper frame-wrapper]]
[app.util.dom :as dom]
[app.util.keyboard :as kbd]
[app.util.object :as obj]
[app.util.timers :as timers]
[beicon.core :as rx]
[cuerdas.core :as str]
[goog.events :as events]
[okulary.core :as l]
[promesa.core :as p]
[rumext.alpha :as mf])
(:import goog.events.EventType))
(defn format-viewbox [vbox]

View file

@ -24,6 +24,7 @@
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.i18n :refer [t] :as i18n]
[app.util.timers :as timers]
[beicon.core :as rx]
[okulary.core :as l]
[potok.core :as ptk]
@ -53,6 +54,10 @@
{:keys [id] :as shape} (:shape mdata)
selected (:selected mdata)
single? (= (count selected) 1)
multiple? (> (count selected) 1)
editable-shape? (#{:group :text :path} (:type shape))
current-file-id (mf/use-ctx ctx/current-file-id)
do-duplicate (st/emitf dw/duplicate-selected)
@ -77,6 +82,9 @@
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
(dwc/start-undo-transaction)
(dwl/update-component id)
@ -99,7 +107,7 @@
: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 shape)))]
(:component-file shape)))]
[:*
[:& menu-entry {:title (t locale "workspace.shape.menu.copy")
:shortcut (sc/get-tooltip :copy)
@ -128,7 +136,7 @@
:on-click do-send-to-back}]
[:& menu-separator]
(when (> (count selected) 1)
(when multiple?
[:*
[:& menu-entry {:title (t locale "workspace.shape.menu.group")
:shortcut (sc/get-tooltip :group)
@ -138,7 +146,7 @@
:on-click do-mask-group}]
[:& menu-separator]])
(when (>= (count selected) 1)
(when (or single? multiple?)
[:*
[:& menu-entry {:title (t locale "workspace.shape.menu.flip-vertical")
:shortcut (sc/get-tooltip :flip-vertical)
@ -148,7 +156,7 @@
:on-click do-flip-horizontal}]
[:& menu-separator]])
(when (and (= (count selected) 1) (= (:type shape) :group))
(when (and single? (= (:type shape) :group))
[:*
[:& menu-entry {:title (t locale "workspace.shape.menu.ungroup")
:shortcut (sc/get-tooltip :ungroup)
@ -161,6 +169,11 @@
:shortcut (sc/get-tooltip :group)
:on-click do-mask-group}])])
(when (and single? editable-shape?)
[:& menu-entry {:title (t locale "workspace.shape.menu.edit")
:shortcut (sc/get-tooltip :start-editing)
:on-click do-start-editing}])
(if (:hidden shape)
[:& menu-entry {:title (t locale "workspace.shape.menu.show")
:on-click do-show-shape}]

View file

@ -9,13 +9,13 @@
(ns app.main.ui.workspace.effects
(:require
[rumext.alpha :as mf]
[app.util.dom :as dom]
[app.main.data.workspace.selection :as dws]
[app.main.store :as st]
[app.main.data.workspace :as dw]
[app.main.data.workspace.selection :as dws]
[app.main.refs :as refs]
[app.main.ui.keyboard :as kbd]))
[app.main.store :as st]
[app.util.dom :as dom]
[app.util.keyboard :as kbd]
[rumext.alpha :as mf]))
(defn use-pointer-enter
[{:keys [id]}]
@ -52,11 +52,9 @@
drawing? @refs/selected-drawing-tool
button (.-which (.-nativeEvent event))
shift? (kbd/shift? event)
ctrl? (or (kbd/ctrl? event) (kbd/meta? event))
allow-click? (and (not blocked)
(not drawing?)
(not ctrl?)
(not edition))]
(when (and (= button 1) allow-click?)

View file

@ -19,10 +19,10 @@
[app.main.store :as st]
[app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.main.ui.workspace.presence :refer [active-sessions]]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[app.util.keyboard :as kbd]
[app.util.router :as rt]
[okulary.core :as l]
[rumext.alpha :as mf]))

View file

@ -10,29 +10,30 @@
(ns app.main.ui.workspace.selection
"Selection handlers component."
(:require
[beicon.core :as rx]
[cuerdas.core :as str]
[potok.core :as ptk]
[rumext.alpha :as mf]
[rumext.util :refer [map->obj]]
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as geom]
[app.common.math :as mth]
[app.common.uuid :as uuid]
[app.util.data :as d]
[app.main.data.workspace :as dw]
[app.main.data.workspace.common :as dwc]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.streams :as ms]
[app.main.ui.cursors :as cur]
[app.common.math :as mth]
[app.main.ui.hooks :as hooks]
[app.main.ui.measurements :as msr]
[app.main.ui.workspace.shapes.outline :refer [outline]]
[app.main.ui.workspace.shapes.path.editor :refer [path-editor]]
[app.util.data :as d]
[app.util.debug :refer [debug?]]
[app.util.dom :as dom]
[app.util.object :as obj]
[app.common.geom.shapes :as geom]
[app.common.geom.point :as gpt]
[app.common.geom.matrix :as gmt]
[app.util.debug :refer [debug?]]
[app.main.ui.workspace.shapes.outline :refer [outline]]
[app.main.ui.measurements :as msr]
[app.main.ui.workspace.shapes.path.editor :refer [path-editor]]))
[beicon.core :as rx]
[cuerdas.core :as str]
[potok.core :as ptk]
[rumext.alpha :as mf]
[rumext.util :refer [map->obj]]))
(def rotation-handler-size 20)
(def resize-point-radius 4)
@ -235,19 +236,22 @@
(mf/defc controls
{::mf/wrap-props false}
[props]
(let [{:keys [overflow-text] :as shape} (obj/get props "shape")
(let [{:keys [overflow-text type] :as shape} (obj/get props "shape")
zoom (obj/get props "zoom")
color (obj/get props "color")
on-resize (obj/get props "on-resize")
on-rotate (obj/get props "on-rotate")
current-transform (mf/deref refs/current-transform)
hide? (mf/use-state false)
selrect (-> (:selrect shape)
minimum-selrect)
transform (geom/transform-matrix shape {:no-flip true})]
(hooks/use-stream ms/keyboard-ctrl #(when (= type :group) (reset! hide? %)))
(when (not (#{:move :rotate} current-transform))
[:g.controls
[:g.controls {:style {:display (when @hide? "none")}}
;; Selection rect
[:& selection-rect {:rect selrect

View file

@ -14,16 +14,16 @@
[app.main.data.workspace :as dw]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.keyboard :as kbd]
[app.main.ui.context :as muc]
[app.main.ui.shapes.frame :as frame]
[app.main.ui.shapes.shape :refer [shape-container]]
[app.main.ui.workspace.effects :as we]
[app.util.dom :as dom]
[app.util.keyboard :as kbd]
[app.util.timers :as ts]
[beicon.core :as rx]
[okulary.core :as l]
[rumext.alpha :as mf]
[app.main.ui.context :as muc]))
[rumext.alpha :as mf]))
(defn use-select-shape [{:keys [id]} edition]
(mf/use-callback

View file

@ -9,17 +9,18 @@
(ns app.main.ui.workspace.shapes.group
(:require
[app.common.geom.shapes :as gsh]
[app.main.data.workspace :as dw]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.streams :as ms]
[app.main.ui.hooks :as hooks]
[app.main.ui.shapes.group :as group]
[app.main.ui.shapes.shape :refer [shape-container]]
[app.main.ui.workspace.effects :as we]
[app.util.debug :refer [debug?]]
[app.util.dom :as dom]
[rumext.alpha :as mf]
[app.common.geom.shapes :as gsh]
[app.util.debug :refer [debug?]]))
[rumext.alpha :as mf]))
(defn use-double-click [{:keys [id]}]
(mf/use-callback
@ -40,8 +41,10 @@
frame (unchecked-get props "frame")
{:keys [id x y width height]} shape
transform (gsh/transform-matrix shape)
transform (gsh/transform-matrix shape)
ctrl? (mf/use-state false)
childs-ref (mf/use-memo (mf/deps shape) #(refs/objects-by-id (:shapes shape)))
childs (mf/deref childs-ref)
@ -59,33 +62,38 @@
is-mask-selected?
(mf/deref is-mask-selected-ref)
expand-mask? is-child-selected?
group-interactions? (not (or @ctrl? is-child-selected?))
handle-mouse-down (we/use-mouse-down shape)
handle-context-menu (we/use-context-menu shape)
handle-pointer-enter (we/use-pointer-enter shape)
handle-pointer-leave (we/use-pointer-leave shape)
handle-double-click (use-double-click shape)]
(hooks/use-stream ms/keyboard-ctrl #(reset! ctrl? %))
[:> shape-container {:shape shape}
[:g.group-shape
[:& group-shape
{:frame frame
:shape shape
:childs childs
:expand-mask is-mask-selected?
:pointer-events (when (not is-child-selected?) "none")}]
:expand-mask expand-mask?
:pointer-events (when group-interactions? "none")}]
(when-not is-child-selected?
[:rect.group-actions
{:x x
:y y
:fill (if (debug? :group) "red" "transparent")
:opacity 0.5
:transform transform
:width width
:height height
:on-mouse-down handle-mouse-down
:on-context-menu handle-context-menu
:on-pointer-over handle-pointer-enter
:on-pointer-out handle-pointer-leave
:on-double-click handle-double-click}])]]))))
[:rect.group-actions
{:x x
:y y
:width width
:height height
:transform transform
:style {:pointer-events (when-not group-interactions? "none")
:fill (if (debug? :group) "red" "transparent")
:opacity 0.5}
:on-mouse-down handle-mouse-down
:on-context-menu handle-context-menu
:on-pointer-over handle-pointer-enter
:on-pointer-out handle-pointer-leave
:on-double-click handle-double-click}]]]))))

View file

@ -10,17 +10,17 @@
(ns app.main.ui.workspace.shapes.interactions
"Visually show shape interactions in workspace"
(:require
[rumext.alpha :as mf]
[cuerdas.core :as str]
[app.util.data :as dt]
[app.util.dom :as dom]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as geom]
[app.main.store :as st]
[app.main.refs :as refs]
[app.main.data.workspace :as dw]
[app.main.ui.keyboard :as kbd]
[app.main.ui.workspace.shapes.outline :refer [outline]]))
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.workspace.shapes.outline :refer [outline]]
[app.util.data :as dt]
[app.util.dom :as dom]
[app.util.keyboard :as kbd]
[cuerdas.core :as str]
[rumext.alpha :as mf]))
(defn- get-click-interaction
[shape]

View file

@ -182,11 +182,9 @@
(and self (.contains self target))
(and cpicker (.contains cpicker target))
(and palette (.contains palette target)))
(do
(if selecting?
(mf/set-ref-val! selecting-ref false)
(on-close))))))
(if selecting?
(mf/set-ref-val! selecting-ref false)
(on-close)))))
on-mouse-down
(fn [event]

View file

@ -26,17 +26,17 @@
[app.main.store :as st]
[app.main.ui.components.color-bullet :as bc]
[app.main.ui.components.context-menu :refer [context-menu]]
[app.main.ui.components.editable-label :refer [editable-label]]
[app.main.ui.components.file-uploader :refer [file-uploader]]
[app.main.ui.components.tab-container :refer [tab-container tab-element]]
[app.main.ui.components.editable-label :refer [editable-label]]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.main.ui.workspace.sidebar.options.typography :refer [typography-entry]]
[app.util.data :refer [matches-search]]
[app.util.dom :as dom]
[app.util.dom.dnd :as dnd]
[app.util.i18n :as i18n :refer [tr t]]
[app.util.keyboard :as kbd]
[app.util.router :as rt]
[app.util.text :as ut]
[app.util.timers :as timers]

View file

@ -18,10 +18,9 @@
[app.main.store :as st]
[app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.main.ui.keyboard :as kbd]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [t]]
[app.util.keyboard :as kbd]
[app.util.object :as obj]
[app.util.perf :as perf]
[app.util.timers :as ts]

View file

@ -9,18 +9,18 @@
(ns app.main.ui.workspace.sidebar.sitemap
(:require
[app.main.ui.components.context-menu :refer [context-menu]]
[app.common.data :as d]
[app.main.data.modal :as modal]
[app.main.data.workspace :as dw]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.context-menu :refer [context-menu]]
[app.main.ui.context :as ctx]
[app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[app.util.keyboard :as kbd]
[app.util.router :as rt]
[cuerdas.core :as str]
[okulary.core :as l]

View file

@ -29,7 +29,6 @@
[app.main.ui.cursors :as cur]
[app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.main.ui.workspace.colorpicker.pixel-overlay :refer [pixel-overlay]]
[app.main.ui.workspace.comments :refer [comments-layer]]
[app.main.ui.workspace.drawarea :refer [draw-area]]
@ -46,6 +45,7 @@
[app.util.dom :as dom]
[app.util.dom.dnd :as dnd]
[app.util.http :as http]
[app.util.keyboard :as kbd]
[app.util.object :as obj]
[app.util.perf :as perf]
[app.util.timers :as timers]
@ -57,7 +57,8 @@
[promesa.core :as p]
[rumext.alpha :as mf])
(:import goog.events.EventType
goog.events.WheelEvent))
goog.events.WheelEvent
goog.events.KeyCodes))
(defonce css-mouse?
(cfg/check-browser? :firefox))
@ -219,11 +220,17 @@
(not (:blocked shape))
(not= edition (:id shape))
(outline? (:id shape))))
shapes (->> (vals objects) (filter show-outline?))
remove-groups? (mf/use-state false)
shapes (cond->> (vals objects)
show-outline? (filter show-outline?)
@remove-groups? (remove #(= :group (:type %))))
transform (mf/deref refs/current-transform)
color (if (or (> (count shapes) 1) (nil? (:shape-ref (first shapes))))
"#31EFB8"
"#00E0FF")]
(hooks/use-stream ms/keyboard-ctrl #(reset! remove-groups? %))
(when (nil? transform)
[:g.outlines
(for [shape shapes]
@ -424,16 +431,16 @@
(mf/use-callback
(fn [event]
(let [target (dom/get-target event)]
; Capture mouse pointer to detect the movements even if cursor
; leaves the viewport or the browser itself
; https://developer.mozilla.org/en-US/docs/Web/API/Element/setPointerCapture
; Capture mouse pointer to detect the movements even if cursor
; leaves the viewport or the browser itself
; https://developer.mozilla.org/en-US/docs/Web/API/Element/setPointerCapture
(.setPointerCapture target (.-pointerId event)))))
on-pointer-up
(mf/use-callback
(fn [event]
(let [target (dom/get-target event)]
; Release pointer on mouse up
; Release pointer on mouse up
(.releasePointerCapture target (.-pointerId event)))))
on-click
@ -442,9 +449,7 @@
(let [ctrl? (kbd/ctrl? event)
shift? (kbd/shift? event)
alt? (kbd/alt? event)]
(if ctrl?
(st/emit! (dw/select-last-layer @ms/mouse-position))
(st/emit! (ms/->MouseEvent :click ctrl? shift? alt?))))))
(st/emit! (ms/->MouseEvent :click ctrl? shift? alt?)))))
on-double-click
(mf/use-callback
@ -460,14 +465,16 @@
(mf/use-callback
(fn [event]
(let [bevent (.getBrowserEvent ^js event)
key (.-keyCode ^js event)
ctrl? (kbd/ctrl? event)
key (.-keyCode ^js event)
key (.normalizeKeyCode KeyCodes key)
ctrl? (kbd/ctrl? event)
shift? (kbd/shift? event)
alt? (kbd/alt? event)
alt? (kbd/alt? event)
meta? (kbd/meta? event)
target (dom/get-target event)]
(when-not (.-repeat bevent)
(st/emit! (ms/->KeyboardEvent :down key ctrl? shift? alt?))
(st/emit! (ms/->KeyboardEvent :down key shift? ctrl? alt? meta?))
(when (and (kbd/space? event)
(not= "rich-text" (obj/get target "className"))
(not= "INPUT" (obj/get target "tagName"))
@ -477,13 +484,15 @@
on-key-up
(mf/use-callback
(fn [event]
(let [key (.-keyCode event)
ctrl? (kbd/ctrl? event)
(let [key (.-keyCode event)
key (.normalizeKeyCode KeyCodes key)
ctrl? (kbd/ctrl? event)
shift? (kbd/shift? event)
alt? (kbd/alt? event)]
alt? (kbd/alt? event)
meta? (kbd/meta? event)]
(when (kbd/space? event)
(st/emit! dw/finish-pan ::finish-positioning))
(st/emit! (ms/->KeyboardEvent :up key ctrl? shift? alt?)))))
(st/emit! (ms/->KeyboardEvent :up key shift? ctrl? alt? meta?)))))
translate-point-to-viewport
(mf/use-callback

View file

@ -1,4 +1,13 @@
(ns app.main.ui.keyboard)
;; 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-2021 UXBOX Labs SL
(ns app.util.keyboard)
(defn is-keycode?
[keycode]