Merge remote-tracking branch 'origin/staging' into develop
Some checks failed
_DEVELOP / build-bundle (push) Has been cancelled
_DEVELOP / build-docker (push) Has been cancelled
_STAGING / build-bundle (push) Has been cancelled
_STAGING / build-docker (push) Has been cancelled
_NITRATE MODULE / build-bundle (push) Has been cancelled
_NITRATE MODULE / build-docker (push) Has been cancelled
Commit Message Check / Check Commit Message (push) Has been cancelled
CI / Linter (push) Has been cancelled
CI / Common Tests (push) Has been cancelled
CI / Frontend Tests (push) Has been cancelled
CI / Render WASM Tests (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Library Tests (push) Has been cancelled
CI / Build Integration Bundle (push) Has been cancelled
CI / Integration Tests 1/4 (push) Has been cancelled
CI / Integration Tests 2/4 (push) Has been cancelled
CI / Integration Tests 3/4 (push) Has been cancelled
CI / Integration Tests 4/4 (push) Has been cancelled

This commit is contained in:
Andrey Antukh
2025-12-09 19:53:38 +01:00
52 changed files with 413 additions and 298 deletions

View File

@@ -111,6 +111,9 @@ example. It's still usable as before, we just removed the example.
- Fix copy/pasting application/transit+json [Taiga #12721](https://tree.taiga.io/project/penpot/issue/12721) - Fix copy/pasting application/transit+json [Taiga #12721](https://tree.taiga.io/project/penpot/issue/12721)
- Fix problem with plugins content attribute [Plugins #209](https://github.com/penpot/penpot-plugins/issues/209) - Fix problem with plugins content attribute [Plugins #209](https://github.com/penpot/penpot-plugins/issues/209)
- Fix U and E icon displayed in project list [Taiga #12806](https://tree.taiga.io/project/penpot/issue/12806) - Fix U and E icon displayed in project list [Taiga #12806](https://tree.taiga.io/project/penpot/issue/12806)
- Fix unpublish library modal not scrolling a long file list [Taiga #12285](https://tree.taiga.io/project/penpot/issue/12285)
- Fix incorrect interaction betwen hower and scroll on assets sidebar [Taiga #12389](https://tree.taiga.io/project/penpot/issue/12389)
- Fix switch variants with paths [Taiga #12841](https://tree.taiga.io/project/penpot/issue/12841)
## 2.11.1 ## 2.11.1

View File

@@ -106,17 +106,17 @@
(let [content-part (MimeBodyPart.) (let [content-part (MimeBodyPart.)
alternative-mpart (MimeMultipart. "alternative")] alternative-mpart (MimeMultipart. "alternative")]
(when-let [content (get body "text/plain")]
(let [text-part (MimeBodyPart.)]
(.setText text-part ^String content ^String charset)
(.addBodyPart alternative-mpart text-part)))
(when-let [content (get body "text/html")] (when-let [content (get body "text/html")]
(let [html-part (MimeBodyPart.)] (let [html-part (MimeBodyPart.)]
(.setContent html-part ^String content (.setContent html-part ^String content
(str "text/html; charset=" charset)) (str "text/html; charset=" charset))
(.addBodyPart alternative-mpart html-part))) (.addBodyPart alternative-mpart html-part)))
(when-let [content (get body "text/plain")]
(let [text-part (MimeBodyPart.)]
(.setText text-part ^String content ^String charset)
(.addBodyPart alternative-mpart text-part)))
(.setContent content-part alternative-mpart) (.setContent content-part alternative-mpart)
(.addBodyPart mixed-mpart content-part)) (.addBodyPart mixed-mpart content-part))

View File

@@ -79,18 +79,6 @@
(remove #(contains? reserved-props (key %)))) (remove #(contains? reserved-props (key %))))
props)) props))
(defn event-from-rpc-params
"Create a base event skeleton with pre-filled some important
data that can be extracted from RPC params object"
[params]
(let [context {:external-session-id (::rpc/external-session-id params)
:external-event-origin (::rpc/external-event-origin params)
:triggered-by (::rpc/handler-name params)}]
{::type "action"
::profile-id (::rpc/profile-id params)
::ip-addr (::rpc/ip-addr params)
::context (d/without-nils context)}))
(defn get-external-session-id (defn get-external-session-id
[request] [request]
(when-let [session-id (yreq/get-header request "x-external-session-id")] (when-let [session-id (yreq/get-header request "x-external-session-id")]
@@ -99,13 +87,24 @@
(str/blank? session-id)) (str/blank? session-id))
session-id))) session-id)))
(defn- get-external-event-origin (defn- get-client-event-origin
[request] [request]
(when-let [origin (yreq/get-header request "x-event-origin")] (when-let [origin (yreq/get-header request "x-event-origin")]
(when-not (or (> (count origin) 256) (when-not (or (= origin "null")
(= origin "null")
(str/blank? origin)) (str/blank? origin))
origin))) (str/prune origin 200))))
(defn get-client-user-agent
[request]
(when-let [user-agent (yreq/get-header request "user-agent")]
(str/prune user-agent 500)))
(defn- get-client-version
[request]
(when-let [origin (yreq/get-header request "x-frontend-version")]
(when-not (or (= origin "null")
(str/blank? origin))
(str/prune origin 100))))
;; --- SPECS ;; --- SPECS
@@ -134,6 +133,33 @@
(def ^:private check-event (def ^:private check-event
(sm/check-fn schema:event)) (sm/check-fn schema:event))
(defn- prepare-context-from-request
[request]
(let [client-event-origin (get-client-event-origin request)
client-version (get-client-version request)
client-user-agent (get-client-user-agent request)
session-id (get-external-session-id request)
token-id (::actoken/id request)]
(d/without-nils
{:external-session-id session-id
:access-token-id (some-> token-id str)
:client-event-origin client-event-origin
:client-user-agent client-user-agent
:client-version client-version
:version (:full cf/version)})))
(defn event-from-rpc-params
"Create a base event skeleton with pre-filled some important
data that can be extracted from RPC params object"
[params]
(let [context (some-> params meta ::http/request prepare-context-from-request)
event {::type "action"
::profile-id (or (::rpc/profile-id params) uuid/zero)
::ip-addr (::rpc/ip-addr params)}]
(cond-> event
(some? context)
(assoc ::context context))))
(defn prepare-event (defn prepare-event
[cfg mdata params result] [cfg mdata params result]
(let [resultm (meta result) (let [resultm (meta result)
@@ -148,18 +174,10 @@
(merge (::props resultm)) (merge (::props resultm))
(dissoc :profile-id) (dissoc :profile-id)
(dissoc :type))) (dissoc :type)))
(clean-props)) (clean-props))
token-id (::actoken/id request) context (merge (::context resultm)
context (-> (::context resultm) (prepare-context-from-request request))
(assoc :external-session-id
(get-external-session-id request))
(assoc :external-event-origin
(get-external-event-origin request))
(assoc :access-token-id (some-> token-id str))
(d/without-nils))
ip-addr (inet/parse-request request)] ip-addr (inet/parse-request request)]
{::type (or (::type resultm) {::type (or (::type resultm)

View File

@@ -12,8 +12,11 @@
[app.common.files.changes-builder :as pcb] [app.common.files.changes-builder :as pcb]
[app.common.files.helpers :as cfh] [app.common.files.helpers :as cfh]
[app.common.files.variant :as cfv] [app.common.files.variant :as cfv]
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.rect :as grc]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.geom.shapes.common :as gco]
[app.common.logging :as log] [app.common.logging :as log]
[app.common.logic.shapes :as cls] [app.common.logic.shapes :as cls]
[app.common.logic.variant-properties :as clvp] [app.common.logic.variant-properties :as clvp]
@@ -25,6 +28,7 @@
[app.common.types.library :as ctl] [app.common.types.library :as ctl]
[app.common.types.page :as ctp] [app.common.types.page :as ctp]
[app.common.types.pages-list :as ctpl] [app.common.types.pages-list :as ctpl]
[app.common.types.path.segment :as segment]
[app.common.types.shape :as cts] [app.common.types.shape :as cts]
[app.common.types.shape-tree :as ctst] [app.common.types.shape-tree :as ctst]
[app.common.types.shape.interactions :as ctsi] [app.common.types.shape.interactions :as ctsi]
@@ -1874,6 +1878,44 @@
roperations' roperations'
uoperations'))))))) uoperations')))))))
(defn- set-path-new-values
[current-shape prev-shape transform]
(let [new-content (segment/transform-content
(:content current-shape)
(gmt/transform-in (gpt/point 0 0) transform))
new-points (-> (segment/content->selrect new-content)
(grc/rect->points))
points-center (gco/points->center new-points)
new-selrect (gsh/calculate-selrect new-points points-center)
shape (assoc current-shape
:content new-content
:points new-points
:selrect new-selrect)
prev-center (segment/content-center (:content prev-shape))
delta (gpt/subtract points-center (first new-points))
new-pos (gpt/subtract prev-center delta)]
(gsh/absolute-move shape new-pos)))
(defn- switch-path-change-value
[prev-shape ;; The shape before the switch
current-shape ;; The shape after the switch (a clean copy)
ref-shape ;; The referenced shape on the main component
;; before the switch
attr]
(let [old-width (-> ref-shape :selrect :width)
new-width (-> prev-shape :selrect :width)
old-height (-> ref-shape :selrect :height)
new-height (-> prev-shape :selrect :height)
transform (-> (gpt/point (/ new-width old-width)
(/ new-height old-height))
(gmt/scale-matrix))
shape (set-path-new-values current-shape prev-shape transform)]
(get shape attr)))
(defn- switch-text-change-value (defn- switch-text-change-value
[prev-content ;; The :content of the text before the switch [prev-content ;; The :content of the text before the switch
@@ -2025,6 +2067,10 @@
(= :content attr) (= :content attr)
(touched attr-group)) (touched attr-group))
path-change?
(and (= :path (:type current-shape))
(contains? #{:points :selrect :content} attr))
;; position-data is a special case because can be affected by :geometry-group and :content-group ;; position-data is a special case because can be affected by :geometry-group and :content-group
;; so, if the position-data changes but the geometry is touched we need to reset the position-data ;; so, if the position-data changes but the geometry is touched we need to reset the position-data
;; so it's calculated again ;; so it's calculated again
@@ -2053,6 +2099,12 @@
(:content origin-ref-shape) (:content origin-ref-shape)
touched) touched)
path-change?
(switch-path-change-value previous-shape
current-shape
origin-ref-shape
attr)
:else :else
(get previous-shape attr))) (get previous-shape attr)))

View File

@@ -284,9 +284,22 @@
(defn check-fn (defn check-fn
"Create a predefined check function" "Create a predefined check function"
[s & {:keys [hint type code]}] [s & {:keys [hint type code]}]
(let [s (delay (schema s)) (let [s #?(:clj
validator* (delay (m/validator @s)) (schema s)
explainer* (delay (m/explainer @s)) :cljs
(try
(schema s)
(catch :default cause
(let [data (ex-data cause)]
(if (= :malli.core/invalid-schema (:type data))
(throw (ex-info
(str "Invalid schema\n"
(pp/pprint-str (:data data)))
{}))
(throw cause))))))
validator* (delay (m/validator s))
explainer* (delay (m/explainer s))
hint (or ^boolean hint "check error") hint (or ^boolean hint "check error")
type (or ^boolean type :assertion) type (or ^boolean type :assertion)
code (or ^boolean code :data-validation)] code (or ^boolean code :data-validation)]

View File

@@ -7,4 +7,5 @@ bb -i '(babashka.wait/wait-for-port "localhost" 9630)';
bb -i '(babashka.wait/wait-for-path "target/app.js")'; bb -i '(babashka.wait/wait-for-path "target/app.js")';
sleep 2; sleep 2;
export NODE_TLS_REJECT_UNAUTHORIZED=0
exec node target/app.js exec node target/app.js

View File

@@ -100,7 +100,7 @@
(def browser-pool-factory (def browser-pool-factory
(letfn [(create [] (letfn [(create []
(p/let [opts #js {:args #js ["--font-render-hinting=none"]} (p/let [opts #js {:args #js ["--allow-insecure-localhost" "--font-render-hinting=none"]}
browser (.launch pw/chromium opts) browser (.launch pw/chromium opts)
id (swap! pool-browser-id inc)] id (swap! pool-browser-id inc)]
(l/info :origin "factory" :action "create" :browser-id id) (l/info :origin "factory" :action "create" :browser-id id)

View File

@@ -74,7 +74,7 @@
(p/fmap (fn [resource] (p/fmap (fn [resource]
(assoc exchange :response/body resource))) (assoc exchange :response/body resource)))
(p/merr (fn [cause] (p/merr (fn [cause]
(l/error :hint "unexpected error on export multiple" (l/error :hint "unexpected error on single export"
:cause cause) :cause cause)
(p/rejected cause)))))) (p/rejected cause))))))
@@ -94,7 +94,7 @@
(redis/pub! topic data)))) (redis/pub! topic data))))
on-error (fn [cause] on-error (fn [cause]
(l/error :hint "unexpected error on multiple exportation" :cause cause) (l/error :hint "unexpected error on multiple export" :cause cause)
(if wait (if wait
(p/rejected cause) (p/rejected cause)
(redis/pub! topic {:type :export-update (redis/pub! topic {:type :export-update

View File

@@ -67,7 +67,7 @@
[] []
(let [uagent (new ua/UAParser)] (let [uagent (new ua/UAParser)]
(merge (merge
{:app-version (:full cf/version) {:version (:full cf/version)
:locale i18n/*current-locale*} :locale i18n/*current-locale*}
(let [browser (.getBrowser uagent)] (let [browser (.getBrowser uagent)]
{:browser (obj/get browser "name") {:browser (obj/get browser "name")

View File

@@ -351,19 +351,31 @@
(on-success)))) (on-success))))
(rx/catch on-error)))))) (rx/catch on-error))))))
(def ^:private schema:create-invitation
[:and
[:map
[:emails {:optional true} [::sm/set ::sm/email]]
[:invitations {:optional true}
[:vector
[:map
[:email ::sm/email]
[:role [::sm/one-of ctt/valid-roles]]]]]
[:team-id ::sm/uuid]
[:resend? {:optional true} ::sm/boolean]]
[:fn (fn [attrs]
(or (contains? attrs :emails)
(contains? attrs :invitations)))]])
(def ^:private check-create-invitations-params
(sm/check-fn schema:create-invitation))
(defn create-invitations (defn create-invitations
"Unified function to create invitations. Supports two parameter formats: "Unified function to create invitations. Supports two parameter formats:
1. {:emails #{...} :role :admin :team-id uuid} - single role for all emails 1. {:emails #{...} :role :admin :team-id uuid} - single role for all emails
2. {:invitations [{:email ... :role ...}] :team-id uuid} - individual roles per email" 2. {:invitations [{:email ... :role ...}] :team-id uuid} - individual roles per email"
[{:keys [emails role team-id invitations resend?] :as params}] [{:keys [emails role team-id invitations resend?] :as params}]
(check-create-invitations-params params)
(assert (uuid? team-id))
;; Validate input format - must have either emails+role OR invitations
(assert (or (and emails role (sm/check-set-of-emails emails) (keyword? role))
(and invitations
(sm/check-set-of-emails (map :email invitations))
(every? #(contains? ctt/valid-roles (:role %)) invitations)))
"Must provide either emails+role or invitations with individual roles")
(ptk/reify ::create-invitations (ptk/reify ::create-invitations
ev/Event ev/Event

View File

@@ -106,14 +106,14 @@
(when (not= 0 count-libraries) (when (not= 0 count-libraries)
(if (pos? (count references)) (if (pos? (count references))
[:* [:*
[:div (when (and (string? scd-msg) (not= scd-msg ""))
(when (and (string? scd-msg) (not= scd-msg "")) [:p {:class (stl/css :modal-scd-msg)} scd-msg])
[:h3 {:class (stl/css :modal-scd-msg)} scd-msg])
[:ul {:class (stl/css :element-list)} [:ul {:class (stl/css :element-list)}
(for [[file-id file-name] references] (for [[file-id file-name] references]
[:li {:class (stl/css :list-item) [:li {:class (stl/css :list-item)
:key (dm/str file-id)} :key (dm/str file-id)}
[:span "- " file-name]])]] [:span "- " file-name]])]
(when (and (string? hint) (not= hint "")) (when (and (string? hint) (not= hint ""))
[:> context-notification* {:level :info [:> context-notification* {:level :info
:appearance :ghost} :appearance :ghost}

View File

@@ -4,7 +4,8 @@
// //
// Copyright (c) KALEIDOS INC // Copyright (c) KALEIDOS INC
@use "refactor/common-refactor.scss" as deprecated; @use "refactor/basic-rules.scss" as *;
@use "ds/typography.scss" as t;
.modal-overlay { .modal-overlay {
@extend .modal-overlay-base; @extend .modal-overlay-base;
@@ -15,14 +16,19 @@
.modal-container { .modal-container {
@extend .modal-container-base; @extend .modal-container-base;
display: grid;
gap: var(--sp-xxl);
grid-template-rows: auto minmax(0, 1fr) auto;
} }
.modal-header { .list-wrapper {
margin-bottom: deprecated.$s-24; display: grid;
grid-template-rows: auto 1fr auto;
max-height: 100%;
} }
.modal-title { .modal-title {
@include deprecated.headlineMediumTypography; @include t.use-typography("headline-medium");
color: var(--modal-title-foreground-color); color: var(--modal-title-foreground-color);
} }
@@ -31,13 +37,16 @@
} }
.modal-content { .modal-content {
@include deprecated.bodySmallTypography; @include t.use-typography("body-small");
margin-bottom: deprecated.$s-24; display: grid;
gap: var(--sp-s);
} }
.element-list { .element-list {
@include deprecated.bodyLargeTypography; @include t.use-typography("body-large");
color: var(--modal-text-foreground-color); color: var(--modal-text-foreground-color);
overflow-y: scroll;
margin-block: 0;
} }
.action-buttons { .action-buttons {
@@ -55,10 +64,14 @@
} }
} }
.modal-scd-msg {
margin-block: 0;
}
.modal-scd-msg, .modal-scd-msg,
.modal-subtitle, .modal-subtitle,
.modal-msg { .modal-msg {
@include deprecated.bodyLargeTypography; @include t.use-typography("body-large");
color: var(--modal-text-foreground-color); color: var(--modal-text-foreground-color);
line-height: 1.5; line-height: 1.5;
} }

View File

@@ -36,7 +36,7 @@
:text [:visibility :geometry :text :shadow :blur :stroke :layout-element] :text [:visibility :geometry :text :shadow :blur :stroke :layout-element]
:variant [:variant :geometry :fill :stroke :shadow :blur :layout :layout-element]}) :variant [:variant :geometry :fill :stroke :shadow :blur :layout :layout-element]})
(mf/defc attributes (mf/defc attributes*
[{:keys [page-id file-id shapes frame from libraries share-id objects color-space]}] [{:keys [page-id file-id shapes frame from libraries share-id objects color-space]}]
(let [shapes (hooks/use-equal-memo shapes) (let [shapes (hooks/use-equal-memo shapes)
first-shape (first shapes) first-shape (first shapes)

View File

@@ -96,7 +96,7 @@
embed-images? (replace-map images-data))] embed-images? (replace-map images-data))]
(str/format page-template style-code markup-code))) (str/format page-template style-code markup-code)))
(mf/defc code (mf/defc code*
[{:keys [shapes frame on-expand from]}] [{:keys [shapes frame on-expand from]}]
(let [style-type* (mf/use-state "css") (let [style-type* (mf/use-state "css")
markup-type* (mf/use-state "html") markup-type* (mf/use-state "html")

View File

@@ -17,8 +17,8 @@
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i] [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]] [app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
[app.main.ui.ds.product.empty-state :refer [empty-state*]] [app.main.ui.ds.product.empty-state :refer [empty-state*]]
[app.main.ui.inspect.attributes :refer [attributes]] [app.main.ui.inspect.attributes :refer [attributes*]]
[app.main.ui.inspect.code :refer [code]] [app.main.ui.inspect.code :refer [code*]]
[app.main.ui.inspect.selection-feedback :refer [resolve-shapes]] [app.main.ui.inspect.selection-feedback :refer [resolve-shapes]]
[app.main.ui.inspect.styles :refer [styles-tab*]] [app.main.ui.inspect.styles :refer [styles-tab*]]
[app.util.dom :as dom] [app.util.dom :as dom]
@@ -123,8 +123,7 @@
(fn [] (fn []
(if (seq shapes) (if (seq shapes)
(st/emit! (ptk/event ::ev/event {::ev/name "inspect-mode-click-element"})) (st/emit! (ptk/event ::ev/event {::ev/name "inspect-mode-click-element"}))
(handle-change-tab (if (contains? cf/flags :inspect-styles) :styles :info))) (handle-change-tab (if (contains? cf/flags :inspect-styles) :styles :info)))))
(reset! color-space* "hex")))
[:aside {:class (stl/css-case :settings-bar-right true [:aside {:class (stl/css-case :settings-bar-right true
:viewer-code (= from :viewer))} :viewer-code (= from :viewer))}
@@ -190,41 +189,41 @@
:libraries libraries :libraries libraries
:file-id file-id}] :file-id file-id}]
:computed :computed
[:& attributes {:color-space color-space [:> attributes* {:color-space color-space
:page-id page-id :page-id page-id
:objects objects :objects objects
:file-id file-id :file-id file-id
:frame frame :frame frame
:shapes shapes :shapes shapes
:from from :from from
:libraries libraries :libraries libraries
:share-id share-id}] :share-id share-id}]
:code :code
[:& code {:frame frame [:> code* {:frame frame
:shapes shapes :shapes shapes
:on-expand handle-expand :on-expand handle-expand
:from from}])] :from from}])]
[:> tab-switcher* {:tabs tabs [:> tab-switcher* {:tabs tabs
:selected (name @section) :selected (name @section)
:on-change handle-change-tab :on-change handle-change-tab
:class (stl/css :viewer-tab-switcher)} :class (stl/css :viewer-tab-switcher)}
(case @section (case @section
:info :info
[:& attributes {:page-id page-id [:> attributes* {:page-id page-id
:objects objects :objects objects
:file-id file-id :file-id file-id
:frame frame :frame frame
:shapes shapes :shapes shapes
:from from :from from
:libraries libraries :libraries libraries
:share-id share-id}] :share-id share-id}]
:code :code
[:& code {:frame frame [:> code* {:frame frame
:shapes shapes :shapes shapes
:on-expand handle-expand :on-expand handle-expand
:from from}])])]] :from from}])])]]
[:* [:*
[:div {:class (stl/css :empty)} [:div {:class (stl/css :empty)}

View File

@@ -133,7 +133,7 @@
(swap! shorthands* assoc (:panel shorthand) (:property shorthand))))] (swap! shorthands* assoc (:panel shorthand) (:property shorthand))))]
[:ol {:class (stl/css :styles-tab) :aria-label (tr "labels.styles")} [:ol {:class (stl/css :styles-tab) :aria-label (tr "labels.styles")}
;; TOKENS PANEL ;; TOKENS PANEL
(when (or active-themes active-sets) (when (or (seq active-themes) (seq active-sets))
[:li [:li
[:> style-box* {:panel :token} [:> style-box* {:panel :token}
[:> tokens-panel* {:theme-paths active-themes :set-names active-sets}]]]) [:> tokens-panel* {:theme-paths active-themes :set-names active-sets}]]])

View File

@@ -6,6 +6,15 @@
@use "ds/typography.scss" as *; @use "ds/typography.scss" as *;
// TODO: this must be a custom property in the design system
:global(.light) {
--low-emphasis-background: #fafafa;
}
:global(.default) {
--low-emphasis-background: #121214;
}
.style-box { .style-box {
--title-gap: var(--sp-xs); --title-gap: var(--sp-xs);
--title-padding: var(--sp-s); --title-padding: var(--sp-s);
@@ -13,12 +22,9 @@
--arrow-color: var(--color-foreground-secondary); --arrow-color: var(--color-foreground-secondary);
--box-border-color: var(--color-background-primary); --box-border-color: var(--color-background-primary);
// TODO: this must be a custom property in the design system
--lowEmphasis-background: #121214;
padding-block: var(--sp-s); padding-block: var(--sp-s);
padding-inline: var(--sp-m); padding-inline: var(--sp-m);
background-color: var(--lowEmphasis-background); background-color: var(--low-emphasis-background);
border-block-end: 2px solid var(--box-border-color); border-block-end: 2px solid var(--box-border-color);
} }

View File

@@ -27,7 +27,7 @@
[app.main.ui.workspace.coordinates :as coordinates] [app.main.ui.workspace.coordinates :as coordinates]
[app.main.ui.workspace.libraries] [app.main.ui.workspace.libraries]
[app.main.ui.workspace.nudge] [app.main.ui.workspace.nudge]
[app.main.ui.workspace.palette :refer [palette]] [app.main.ui.workspace.palette :refer [palette*]]
[app.main.ui.workspace.plugins] [app.main.ui.workspace.plugins]
[app.main.ui.workspace.sidebar :refer [sidebar*]] [app.main.ui.workspace.sidebar :refer [sidebar*]]
[app.main.ui.workspace.sidebar.history :refer [history-toolbox*]] [app.main.ui.workspace.sidebar.history :refer [history-toolbox*]]
@@ -84,8 +84,8 @@
node-ref (use-resize-observer on-resize)] node-ref (use-resize-observer on-resize)]
[:* [:*
(when (not ^boolean hide-ui?) (when (not ^boolean hide-ui?)
[:& palette {:layout layout [:> palette* {:layout layout
:on-change-palette-size on-resize-palette}]) :on-change-size on-resize-palette}])
[:section [:section
{:key (dm/str "workspace-" page-id) {:key (dm/str "workspace-" page-id)

View File

@@ -156,7 +156,7 @@
(let [{:keys [modal title]} (get dwta/token-properties :color) (let [{:keys [modal title]} (get dwta/token-properties :color)
window-size (dom/get-window-size) window-size (dom/get-window-size)
left-sidebar (dom/get-element "left-sidebar-aside") left-sidebar (dom/get-element "left-sidebar-aside")
x-size (dom/get-data left-sidebar "left-sidebar-width") x-size (dom/get-data left-sidebar "width")
modal-height 392 modal-height 392
x (- (int x-size) 30) x (- (int x-size) 30)
y (- (/ (:height window-size) 2) (/ modal-height 2))] y (- (/ (:height window-size) 2) (/ modal-height 2))]

View File

@@ -33,12 +33,13 @@
[okulary.core :as l] [okulary.core :as l]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(def viewport (def ^:private ref:viewport
(l/derived :vport refs/workspace-local)) (l/derived :vport refs/workspace-local))
(defn calculate-palette-padding [rulers?] (defn- calculate-palette-style
[rulers?]
(let [left-sidebar (dom/get-element "left-sidebar-aside") (let [left-sidebar (dom/get-element "left-sidebar-aside")
left-sidebar-size (-> (dom/get-data left-sidebar "left-sidebar-width") left-sidebar-size (-> (dom/get-data left-sidebar "width")
(d/parse-integer)) (d/parse-integer))
rulers-width (if rulers? 22 0) rulers-width (if rulers? 22 0)
min-left-sidebar-width left-sidebar-default-width min-left-sidebar-width left-sidebar-default-width
@@ -48,36 +49,46 @@
#js {"paddingLeft" (dm/str calculate-padding-left "px") #js {"paddingLeft" (dm/str calculate-padding-left "px")
"paddingRight" "322px"})) "paddingRight" "322px"}))
(mf/defc palette (mf/defc palette*
[{:keys [layout on-change-palette-size]}] [{:keys [layout on-change-size]}]
(let [color-palette? (:colorpalette layout) (let [color-palette? (:colorpalette layout)
text-palette? (:textpalette layout) text-palette? (:textpalette layout)
hide-palettes? (:hide-palettes layout) hide-palettes? (:hide-palettes layout)
workspace-read-only? (mf/use-ctx ctx/workspace-read-only?)
container (mf/use-ref nil)
state* (mf/use-state {:show-menu false})
state (deref state*)
show-menu? (:show-menu state)
selected (h/use-shared-state mdc/colorpalette-selected-broadcast-key :recent)
selected-text* (mf/use-state :file)
selected-text (deref selected-text*)
on-select (mf/use-fn #(reset! selected %))
rulers? (mf/deref refs/rulers?)
{:keys [on-pointer-down on-lost-pointer-capture on-pointer-move parent-ref size]}
(r/use-resize-hook :palette 72 54 80 :y true :bottom on-change-palette-size)
vport (mf/deref viewport) read-only? (mf/use-ctx ctx/workspace-read-only?)
vport-width (:width vport) container (mf/use-ref nil)
state* (mf/use-state #(-> {:show-menu false}))
state (deref state*)
show-menu? (:show-menu state)
selected (h/use-shared-state mdc/colorpalette-selected-broadcast-key :recent)
selected-text* (mf/use-state :file)
selected-text (deref selected-text*)
on-select (mf/use-fn #(reset! selected %))
rulers? (mf/deref refs/rulers?)
vport (mf/deref ref:viewport)
vport-width (get vport :width)
{:keys [on-pointer-down
on-lost-pointer-capture
on-pointer-move
parent-ref
size]}
(r/use-resize-hook :palette 72 54 80 :y true :bottom on-change-size)
on-resize on-resize
(mf/use-callback (mf/use-fn
(fn [_] (fn [_]
(let [dom (mf/ref-val container) (let [dom (mf/ref-val container)
width (obj/get dom "clientWidth")] width (obj/get dom "clientWidth")]
(swap! state* assoc :width width)))) (swap! state* assoc :width width))))
on-close-menu on-close-menu
(mf/use-callback (mf/use-fn
(fn [_] (fn [_]
(swap! state* assoc :show-menu false))) (swap! state* assoc :show-menu false)))
@@ -100,7 +111,7 @@
(reset! selected-text* (:id lib))))) (reset! selected-text* (:id lib)))))
toggle-palettes toggle-palettes
(mf/use-callback (mf/use-fn
(fn [_] (fn [_]
(r/set-resize-type! :top) (r/set-resize-type! :top)
(dom/add-class! (dom/get-element-by-class "color-palette") "fade-out-down") (dom/add-class! (dom/get-element-by-class "color-palette") "fade-out-down")
@@ -131,7 +142,9 @@
(vary-meta assoc ::ev/origin "workspace-left-toolbar")))) (vary-meta assoc ::ev/origin "workspace-left-toolbar"))))
(dom/blur! node)))) (dom/blur! node))))
any-palette? (or color-palette? text-palette?) any-palette?
(or color-palette? text-palette?)
size-classname size-classname
(cond (cond
(<= size 64) (stl/css :small-palette) (<= size 64) (stl/css :small-palette)
@@ -142,16 +155,16 @@
(let [key1 (events/listen js/window "resize" on-resize)] (let [key1 (events/listen js/window "resize" on-resize)]
#(events/unlistenByKey key1))) #(events/unlistenByKey key1)))
(mf/use-layout-effect (mf/with-layout-effect []
#(let [dom (mf/ref-val parent-ref) (let [dom (mf/ref-val parent-ref)
width (obj/get dom "clientWidth")] width (obj/get dom "clientWidth")]
(swap! state* assoc :width width))) (swap! state* assoc :width width)))
[:div {:class (stl/css :palette-wrapper) [:div {:class (stl/css :palette-wrapper)
:id "palette-wrapper" :id "palette-wrapper"
:style (calculate-palette-padding rulers?) :style (calculate-palette-style rulers?)
:data-testid "palette"} :data-testid "palette"}
(when-not workspace-read-only? (when-not ^boolean read-only?
[:div {:ref parent-ref [:div {:ref parent-ref
:class (dm/str size-classname " " (stl/css-case :palettes true :class (dm/str size-classname " " (stl/css-case :palettes true
:wide any-palette? :wide any-palette?

View File

@@ -27,7 +27,6 @@
[app.main.ui.workspace.left-header :refer [left-header*]] [app.main.ui.workspace.left-header :refer [left-header*]]
[app.main.ui.workspace.right-header :refer [right-header*]] [app.main.ui.workspace.right-header :refer [right-header*]]
[app.main.ui.workspace.sidebar.assets :refer [assets-toolbox*]] [app.main.ui.workspace.sidebar.assets :refer [assets-toolbox*]]
[app.main.ui.workspace.sidebar.collapsable-button :refer [collapsed-button*]]
[app.main.ui.workspace.sidebar.debug :refer [debug-panel*]] [app.main.ui.workspace.sidebar.debug :refer [debug-panel*]]
[app.main.ui.workspace.sidebar.debug-shape-info :refer [debug-shape-info*]] [app.main.ui.workspace.sidebar.debug-shape-info :refer [debug-shape-info*]]
[app.main.ui.workspace.sidebar.history :refer [history-toolbox*]] [app.main.ui.workspace.sidebar.history :refer [history-toolbox*]]
@@ -44,19 +43,34 @@
;; --- Left Sidebar (Component) ;; --- Left Sidebar (Component)
(defn- on-collapse-left-sidebar (def ^:private toggle-collapse-left-sidebar
[] (partial st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))
(st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))
(mf/defc collapse-button* (mf/defc collapse-button*
{::mf/private true}
[] []
;; NOTE: This custom button may be replace by an action button when this variant is designed ;; NOTE: This custom button may be replace by an action button when this variant is designed
[:button {:class (stl/css :collapse-sidebar-button) [:button {:class (stl/css :collapse-sidebar-button)
:on-click on-collapse-left-sidebar} :on-click toggle-collapse-left-sidebar}
[:> icon* {:icon-id i/arrow [:> icon* {:icon-id i/arrow
:size "s" :size "s"
:aria-label (tr "workspace.sidebar.collapse")}]]) :aria-label (tr "workspace.sidebar.collapse")}]])
(mf/defc collapsed-button*
{::mf/memo true
::mf/private true}
[]
[:div {:id "left-sidebar-aside"
:data-width "0"
:class (stl/css :collapsed-sidebar)}
[:div {:class (stl/css :collapsed-title)}
[:button {:class (stl/css :collapsed-button)
:title (tr "workspace.sidebar.expand")
:on-click toggle-collapse-left-sidebar}
[:> icon* {:icon-id i/arrow
:size "s"
:aria-label (tr "workspace.sidebar.expand")}]]]])
(mf/defc layers-content* (mf/defc layers-content*
{::mf/private true {::mf/private true
::mf/memo true} ::mf/memo true}
@@ -97,6 +111,7 @@
[:> layers-toolbox* {:size-parent width}]])) [:> layers-toolbox* {:size-parent width}]]))
(mf/defc left-sidebar* (mf/defc left-sidebar*
{::mf/memo true} {::mf/memo true}
[{:keys [layout file page-id tokens-lib active-tokens resolved-active-tokens]}] [{:keys [layout file page-id tokens-lib active-tokens resolved-active-tokens]}]
@@ -161,7 +176,7 @@
[:aside {:ref parent-ref [:aside {:ref parent-ref
:id "left-sidebar-aside" :id "left-sidebar-aside"
:data-testid "left-sidebar" :data-testid "left-sidebar"
:data-left-sidebar-width (str width) :data-width (str width)
:class aside-class :class aside-class
:style {:--left-sidebar-width (dm/str width "px")}} :style {:--left-sidebar-width (dm/str width "px")}}

View File

@@ -116,6 +116,44 @@
} }
} }
.collapsed-sidebar {
@include deprecated.flexCenter;
position: absolute;
top: deprecated.$s-48;
left: 0;
padding: deprecated.$s-4;
border-radius: deprecated.$br-8;
background: var(--color-background-primary);
margin-inline-start: var(--sp-m);
}
.collapsed-title {
@include deprecated.flexCenter;
height: deprecated.$s-36;
width: deprecated.$s-24;
border-radius: deprecated.$br-8;
background: var(--color-background-secondary);
}
.collapsed-button {
@include deprecated.buttonStyle;
height: deprecated.$s-24;
width: deprecated.$s-16;
padding: 0;
border-radius: deprecated.$br-5;
svg {
@include deprecated.flexCenter;
height: deprecated.$s-16;
width: deprecated.$s-16;
color: transparent;
fill: none;
stroke: var(--icon-foreground);
}
&:hover {
svg {
stroke: var(--icon-foreground-hover);
}
}
}
.versions-tab { .versions-tab {
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;

View File

@@ -56,9 +56,8 @@
(update file :data dissoc :pages-index)) (update file :data dissoc :pages-index))
refs/file)) refs/file))
(mf/defc assets-local-library (mf/defc assets-local-library*
{::mf/wrap [mf/memo] {::mf/private true}
::mf/wrap-props false}
[{:keys [filters]}] [{:keys [filters]}]
(let [file (mf/deref ref:local-library)] (let [file (mf/deref ref:local-library)]
[:> file-library* [:> file-library*
@@ -68,7 +67,7 @@
:filters filters}])) :filters filters}]))
(defn- toggle-values (defn- toggle-values
[v [a b]] [v a b]
(if (= v a) b a)) (if (= v a) b a))
(mf/defc assets-toolbox* (mf/defc assets-toolbox*
@@ -97,7 +96,7 @@
(mf/use-fn (mf/use-fn
(mf/deps ordering) (mf/deps ordering)
(fn [] (fn []
(let [new-value (toggle-values ordering [:asc :desc])] (let [new-value (toggle-values ordering :asc :desc)]
(swap! filters* assoc :ordering new-value) (swap! filters* assoc :ordering new-value)
(dwa/set-current-assets-ordering! new-value)))) (dwa/set-current-assets-ordering! new-value))))
@@ -105,7 +104,7 @@
(mf/use-fn (mf/use-fn
(mf/deps list-style) (mf/deps list-style)
(fn [] (fn []
(let [new-value (toggle-values list-style [:thumbs :list])] (let [new-value (toggle-values list-style :thumbs :list)]
(swap! filters* assoc :list-style new-value) (swap! filters* assoc :list-style new-value)
(dwa/set-current-assets-list-style! new-value)))) (dwa/set-current-assets-list-style! new-value))))
@@ -209,5 +208,5 @@
[:& (mf/provider cmm/assets-toggle-ordering) {:value toggle-ordering} [:& (mf/provider cmm/assets-toggle-ordering) {:value toggle-ordering}
[:& (mf/provider cmm/assets-toggle-list-style) {:value toggle-list-style} [:& (mf/provider cmm/assets-toggle-list-style) {:value toggle-list-style}
[:* [:*
[:& assets-local-library {:filters filters}] [:> assets-local-library* {:filters filters}]
[:> assets-libraries* {:filters filters}]]]]]])) [:> assets-libraries* {:filters filters}]]]]]]))

View File

@@ -15,7 +15,7 @@
cursor: pointer; cursor: pointer;
.title-menu { .title-menu {
display: block; visibility: visible;
} }
} }
} }
@@ -25,7 +25,7 @@
} }
.title-menu { .title-menu {
display: none; visibility: hidden;
} }
.group-title { .group-title {

View File

@@ -1,29 +0,0 @@
;; 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/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.workspace.sidebar.collapsable-button
(:require-macros [app.main.style :as stl])
(:require
[app.main.data.workspace :as dw]
[app.main.store :as st]
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
[app.util.i18n :refer [tr]]
[rumext.v2 :as mf]))
(mf/defc collapsed-button*
{::mf/memo true}
[]
(let [on-click (mf/use-fn #(st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))]
[:div {:id "left-sidebar-aside"
:data-size "0"
:class (stl/css :collapsed-sidebar)}
[:div {:class (stl/css :collapsed-title)}
[:button {:class (stl/css :collapsed-button)
:title (tr "workspace.sidebar.expand")
:on-click on-click}
[:> icon* {:icon-id i/arrow
:size "s"
:aria-label (tr "workspace.sidebar.expand")}]]]]))

View File

@@ -1,45 +0,0 @@
// 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/.
//
// Copyright (c) KALEIDOS INC
@use "refactor/common-refactor.scss" as deprecated;
.collapsed-sidebar {
@include deprecated.flexCenter;
position: absolute;
top: deprecated.$s-48;
left: 0;
padding: deprecated.$s-4;
border-radius: deprecated.$br-8;
background: var(--color-background-primary);
margin-inline-start: var(--sp-m);
}
.collapsed-title {
@include deprecated.flexCenter;
height: deprecated.$s-36;
width: deprecated.$s-24;
border-radius: deprecated.$br-8;
background: var(--color-background-secondary);
}
.collapsed-button {
@include deprecated.buttonStyle;
height: deprecated.$s-24;
width: deprecated.$s-16;
padding: 0;
border-radius: deprecated.$br-5;
svg {
@include deprecated.flexCenter;
height: deprecated.$s-16;
width: deprecated.$s-16;
color: transparent;
fill: none;
stroke: var(--icon-foreground);
}
&:hover {
svg {
stroke: var(--icon-foreground-hover);
}
}
}

View File

@@ -686,7 +686,7 @@
(str/upper (tr "workspace.assets.local-library")) (str/upper (tr "workspace.assets.local-library"))
(dm/get-in libraries [current-library-id :name])) (dm/get-in libraries [current-library-id :name]))
current-lib-data (mf/with-memo [libraries] current-lib-data (mf/with-memo [libraries current-library-id]
(get-in libraries [current-library-id :data])) (get-in libraries [current-library-id :data]))
current-lib-counts (mf/with-memo [current-lib-data] current-lib-counts (mf/with-memo [current-lib-data]

View File

@@ -149,9 +149,9 @@
canvas-ref (mf/use-ref nil) canvas-ref (mf/use-ref nil)
;; VARS ;; STATE REFS
disable-paste (mf/use-var false) disable-paste-ref (mf/use-ref false)
in-viewport? (mf/use-var false) in-viewport-ref (mf/use-ref false)
;; STREAMS ;; STREAMS
move-stream (mf/use-memo #(rx/subject)) move-stream (mf/use-memo #(rx/subject))
@@ -210,10 +210,10 @@
on-pointer-down (actions/on-pointer-down @hover selected edition drawing-tool text-editing? path-editing? grid-editing? on-pointer-down (actions/on-pointer-down @hover selected edition drawing-tool text-editing? path-editing? grid-editing?
path-drawing? create-comment? space? panning z? read-only?) path-drawing? create-comment? space? panning z? read-only?)
on-pointer-up (actions/on-pointer-up disable-paste) on-pointer-up (actions/on-pointer-up disable-paste-ref)
on-pointer-enter (actions/on-pointer-enter in-viewport?) on-pointer-enter (actions/on-pointer-enter in-viewport-ref)
on-pointer-leave (actions/on-pointer-leave in-viewport?) on-pointer-leave (actions/on-pointer-leave in-viewport-ref)
on-pointer-move (actions/on-pointer-move move-stream) on-pointer-move (actions/on-pointer-move move-stream)
on-move-selected (actions/on-move-selected hover hover-ids selected space? z? read-only?) on-move-selected (actions/on-move-selected hover hover-ids selected space? z? read-only?)
on-menu-selected (actions/on-menu-selected hover hover-ids selected read-only?) on-menu-selected (actions/on-menu-selected hover hover-ids selected read-only?)
@@ -304,7 +304,7 @@
#(st/emit! #(st/emit!
(dwv/add-new-variant (:id first-shape))))] (dwv/add-new-variant (:id first-shape))))]
(hooks/setup-dom-events zoom disable-paste in-viewport? read-only? drawing-tool path-drawing?) (hooks/setup-dom-events zoom disable-paste-ref in-viewport-ref read-only? drawing-tool path-drawing?)
(hooks/setup-viewport-size vport viewport-ref) (hooks/setup-viewport-size vport viewport-ref)
(hooks/setup-cursor cursor alt? mod? space? panning drawing-tool path-drawing? path-editing? z? read-only?) (hooks/setup-cursor cursor alt? mod? space? panning drawing-tool path-drawing? path-editing? z? read-only?)
(hooks/setup-keyboard alt? mod? space? z? shift?) (hooks/setup-keyboard alt? mod? space? z? shift?)

View File

@@ -266,7 +266,7 @@
(st/emit! (dw/show-shape-context-menu {:position position :hover-ids @hover-ids}))))))) (st/emit! (dw/show-shape-context-menu {:position position :hover-ids @hover-ids})))))))
(defn on-pointer-up (defn on-pointer-up
[disable-paste] [disable-paste-ref]
(mf/use-callback (mf/use-callback
(fn [event] (fn [event]
(dom/stop-propagation event) (dom/stop-propagation event)
@@ -291,21 +291,19 @@
(dom/prevent-default event) (dom/prevent-default event)
;; We store this so in Firefox the middle button won't do a paste of the content ;; We store this so in Firefox the middle button won't do a paste of the content
(reset! disable-paste true) (mf/set-ref-val! disable-paste-ref true)
(ts/schedule #(reset! disable-paste false))) (ts/schedule #(mf/set-ref-val! disable-paste-ref false)))
(st/emit! (dw/finish-panning) (st/emit! (dw/finish-panning)
(dw/finish-zooming)))))) (dw/finish-zooming))))))
(defn on-pointer-enter [in-viewport?] (defn on-pointer-enter
(mf/use-callback [in-viewport-ref]
(fn [] (mf/use-fn #(mf/set-ref-val! in-viewport-ref true)))
(reset! in-viewport? true))))
(defn on-pointer-leave [in-viewport?] (defn on-pointer-leave
(mf/use-callback [in-viewport-ref]
(fn [] (mf/use-fn #(mf/set-ref-val! in-viewport-ref false)))
(reset! in-viewport? false))))
(defn on-key-down [] (defn on-key-down []
(mf/use-callback (mf/use-callback
@@ -524,15 +522,22 @@
:blobs (seq files)}] :blobs (seq files)}]
(st/emit! (dwm/upload-media-workspace params)))))))) (st/emit! (dwm/upload-media-workspace params))))))))
(def ^:private invalid-paste-targets
#{"INPUT" "TEXTAREA"})
(defn on-paste (defn on-paste
[disable-paste in-viewport? read-only?] [disable-paste-ref in-viewport-ref read-only?]
(mf/use-fn (mf/use-fn
(mf/deps read-only?) (mf/deps read-only?)
(fn [event] (fn [event]
;; We disable the paste just after mouse-up of a middle button so ;; We disable the paste when: 1. just after mouse-up of a middle
;; when panning won't paste the content into the workspace ;; button (so when panning won't paste the content into the
(let [tag-name (-> event dom/get-target dom/get-tag-name)] ;; workspace); 2. when we paste content in an input on the
(when (and (not (#{"INPUT" "TEXTAREA"} tag-name)) ;; sidebar
(not @disable-paste) (let [tag-name (-> event dom/get-target dom/get-tag-name)
disable-paste? (mf/ref-val disable-paste-ref)
in-viewport? (mf/ref-val in-viewport-ref)]
(when (and (not (contains? invalid-paste-targets tag-name))
(not disable-paste?)
(not read-only?)) (not read-only?))
(st/emit! (dw/paste-from-event event @in-viewport?))))))) (st/emit! (dw/paste-from-event event in-viewport?)))))))

View File

@@ -42,11 +42,12 @@
[rumext.v2 :as mf]) [rumext.v2 :as mf])
(:import goog.events.EventType)) (:import goog.events.EventType))
(defn setup-dom-events [zoom disable-paste in-viewport? workspace-read-only? drawing-tool drawing-path?] (defn setup-dom-events
[zoom disable-paste-ref in-viewport-ref workspace-read-only? drawing-tool drawing-path?]
(let [on-key-down (actions/on-key-down) (let [on-key-down (actions/on-key-down)
on-key-up (actions/on-key-up) on-key-up (actions/on-key-up)
on-mouse-wheel (actions/on-mouse-wheel zoom) on-mouse-wheel (actions/on-mouse-wheel zoom)
on-paste (actions/on-paste disable-paste in-viewport? workspace-read-only?) on-paste (actions/on-paste disable-paste-ref in-viewport-ref workspace-read-only?)
on-pointer-down (mf/use-fn on-pointer-down (mf/use-fn
(mf/deps drawing-tool drawing-path?) (mf/deps drawing-tool drawing-path?)
(fn [e] (fn [e]
@@ -56,27 +57,27 @@
(st/emit! (dwe/clear-edition-mode)))))) (st/emit! (dwe/clear-edition-mode))))))
on-blur (mf/use-fn #(st/emit! (mse/->BlurEvent)))] on-blur (mf/use-fn #(st/emit! (mse/->BlurEvent)))]
(mf/use-effect (mf/with-effect [drawing-tool drawing-path?]
(mf/deps drawing-tool drawing-path?) (let [key (events/listen js/window EventType.POINTERDOWN on-pointer-down)]
(fn []
(let [keys [(events/listen js/window EventType.POINTERDOWN on-pointer-down)]]
(fn []
(doseq [key keys]
(events/unlistenByKey key))))))
(mf/use-layout-effect ;; We need to disable workspace paste when we on comments
(mf/deps on-key-down on-key-up on-mouse-wheel on-paste workspace-read-only?) (if (= drawing-tool :comments)
(fn [] (mf/set-ref-val! disable-paste-ref true)
(let [keys [(events/listen js/document EventType.KEYDOWN on-key-down) (mf/set-ref-val! disable-paste-ref false))
(events/listen js/document EventType.KEYUP on-key-up)
;; bind with passive=false to allow the event to be cancelled #(events/unlistenByKey key)))
;; https://stackoverflow.com/a/57582286/3219895
(events/listen js/window EventType.WHEEL on-mouse-wheel #js {:passive false}) (mf/with-layout-effect [on-key-down on-key-up on-mouse-wheel on-paste workspace-read-only?]
(events/listen js/window EventType.PASTE on-paste) (let [keys [(events/listen js/document EventType.KEYDOWN on-key-down)
(events/listen js/window EventType.BLUR on-blur)]] (events/listen js/document EventType.KEYUP on-key-up)
(fn [] ;; bind with passive=false to allow the event to be cancelled
(doseq [key keys] ;; https://stackoverflow.com/a/57582286/3219895
(events/unlistenByKey key)))))))) (events/listen js/window EventType.WHEEL on-mouse-wheel #js {:passive false})
(events/listen js/window EventType.PASTE on-paste)
(events/listen js/window EventType.BLUR on-blur)]]
(fn []
(doseq [key keys]
(events/unlistenByKey key)))))))
(defn setup-viewport-size [vport viewport-ref] (defn setup-viewport-size [vport viewport-ref]
(mf/with-effect [vport] (mf/with-effect [vport]

View File

@@ -142,9 +142,9 @@
canvas-ref (mf/use-ref nil) canvas-ref (mf/use-ref nil)
text-editor-ref (mf/use-ref nil) text-editor-ref (mf/use-ref nil)
;; VARS ;; STATE REFS
disable-paste (mf/use-var false) disable-paste-ref (mf/use-ref false)
in-viewport? (mf/use-var false) in-viewport-ref (mf/use-ref false)
;; STREAMS ;; STREAMS
move-stream (mf/use-memo #(rx/subject)) move-stream (mf/use-memo #(rx/subject))
@@ -204,10 +204,10 @@
on-pointer-down (actions/on-pointer-down @hover selected edition drawing-tool text-editing? path-editing? grid-editing? on-pointer-down (actions/on-pointer-down @hover selected edition drawing-tool text-editing? path-editing? grid-editing?
path-drawing? create-comment? space? panning z? read-only?) path-drawing? create-comment? space? panning z? read-only?)
on-pointer-up (actions/on-pointer-up disable-paste) on-pointer-up (actions/on-pointer-up disable-paste-ref)
on-pointer-enter (actions/on-pointer-enter in-viewport?) on-pointer-enter (actions/on-pointer-enter in-viewport-ref)
on-pointer-leave (actions/on-pointer-leave in-viewport?) on-pointer-leave (actions/on-pointer-leave in-viewport-ref)
on-pointer-move (actions/on-pointer-move move-stream) on-pointer-move (actions/on-pointer-move move-stream)
on-move-selected (actions/on-move-selected hover hover-ids selected space? z? read-only?) on-move-selected (actions/on-move-selected hover hover-ids selected space? z? read-only?)
on-menu-selected (actions/on-menu-selected hover hover-ids selected read-only?) on-menu-selected (actions/on-menu-selected hover hover-ids selected read-only?)
@@ -349,7 +349,7 @@
(wasm.api/show-grid @hover-top-frame-id) (wasm.api/show-grid @hover-top-frame-id)
(wasm.api/clear-grid)))) (wasm.api/clear-grid))))
(hooks/setup-dom-events zoom disable-paste in-viewport? read-only? drawing-tool path-drawing?) (hooks/setup-dom-events zoom disable-paste-ref in-viewport-ref read-only? drawing-tool path-drawing?)
(hooks/setup-viewport-size vport viewport-ref) (hooks/setup-viewport-size vport viewport-ref)
(hooks/setup-cursor cursor alt? mod? space? panning drawing-tool path-drawing? path-editing? z? read-only?) (hooks/setup-cursor cursor alt? mod? space? panning drawing-tool path-drawing? path-editing? z? read-only?)
(hooks/setup-keyboard alt? mod? space? z? shift?) (hooks/setup-keyboard alt? mod? space? z? shift?)

View File

@@ -57,10 +57,11 @@
(= (dom/get-tag-name target) "INPUT")] (= (dom/get-tag-name target) "INPUT")]
;; ignore when pasting into an editable control ;; ignore when pasting into an editable control
(when-not (or content-editable? is-input?) (if-not (or content-editable? is-input?)
(-> event (-> event
(dom/event->browser-event) (dom/event->browser-event)
(from-clipboard-event options)))))) (from-clipboard-event options))
(rx/empty)))))
(defn from-drop-event (defn from-drop-event
"Get clipboard stream from drop event" "Get clipboard stream from drop event"

View File

@@ -392,7 +392,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"els fitxers amb biblioteques compartides sinclouran a lexportació, " "Els fitxers amb biblioteques compartides sinclouran a lexportació, "
"mantenint la vinculació." "mantenint la vinculació."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -542,7 +542,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"soubory se sdílenými knihovnami budou zahrnuty do exportu, čímž se zachová " "Soubory se sdílenými knihovnami budou zahrnuty do exportu, čímž se zachová "
"jejich propojení." "jejich propojení."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -576,7 +576,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"files with shared libraries will be included in the export, maintaining " "Files with shared libraries will be included in the export, maintaining "
"their linkage." "their linkage."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -585,7 +585,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"ficheros con librerias compartidas se inclurán en el paquete de exportación " "Ficheros con librerias compartidas se inclurán en el paquete de exportación "
"y mantendrán los enlaces." "y mantendrán los enlaces."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -370,7 +370,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"partekatutako liburutegiak dituzten fitxategiak esportazio paketean sartuko " "Partekatutako liburutegiak dituzten fitxategiak esportazio paketean sartuko "
"dira eta loturak mantenduko dituzte." "dira eta loturak mantenduko dituzte."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -368,7 +368,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"os ficheiros con bibliotecas compartidas incluiranse na exportación " "Os ficheiros con bibliotecas compartidas incluiranse na exportación "
"mantendo os vínculos." "mantendo os vínculos."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -430,7 +430,7 @@ msgstr "za ka iya fitar da kundi daya ko fiye ta hanyar tura taska. \"me \"*?"
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "manhajar tura kundi ta kunshi fitarwa, tattali mahaxarsu." msgstr "Manhajar tura kundi ta kunshi fitarwa, tattali mahaxarsu."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165
msgid "dashboard.export.options.all.title" msgid "dashboard.export.options.all.title"

View File

@@ -541,7 +541,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"datoteke sa zajedničkim bibliotekama bit će uključene u izvoz, održavajući " "Datoteke sa zajedničkim bibliotekama bit će uključene u izvoz, održavajući "
"njihovu poveznicu." "njihovu poveznicu."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -573,7 +573,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "berkas dengan pustaka bersama akan dimasukkan dalam hasil ekspor." msgstr "Berkas dengan pustaka bersama akan dimasukkan dalam hasil ekspor."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165
msgid "dashboard.export.options.all.title" msgid "dashboard.export.options.all.title"

View File

@@ -346,7 +346,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"failai su bendromis bibliotekomis bus įtraukti į eksportą, išlaikant jų " "Failai su bendromis bibliotekomis bus įtraukti į eksportą, išlaikant jų "
"susiejimą." "susiejimą."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -584,7 +584,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"izguvē tiks iekļautas datnes ar koplietojamām bibliotēkām, saglabājot to " "Izguvē tiks iekļautas datnes ar koplietojamām bibliotēkām, saglabājot to "
"sasaisti." "sasaisti."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -438,7 +438,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"fail dengan perpustakaan kongsi akan disertakan dalam eksport, mengekalkan " "Fail dengan perpustakaan kongsi akan disertakan dalam eksport, mengekalkan "
"hubungannya." "hubungannya."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -372,7 +372,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"pliki z bibliotekami współdzielonymi zostaną uwzględnione w eksporcie, z " "Pliki z bibliotekami współdzielonymi zostaną uwzględnione w eksporcie, z "
"zachowaniem ich powiązania." "zachowaniem ich powiązania."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -581,7 +581,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"arquivos com bibliotecas compartilhadas serão incluídos na exportação, " "Arquivos com bibliotecas compartilhadas serão incluídos na exportação, "
"mantendo seu vínculo." "mantendo seu vínculo."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -555,7 +555,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"ficheiros com bibliotecas partilhadas serão incluídos na exportação, " "Ficheiros com bibliotecas partilhadas serão incluídos na exportação, "
"mantendo as ligações." "mantendo as ligações."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -590,7 +590,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"fișierele cu biblioteci partajate vor fi incluse în export, menținându-le " "Fișierele cu biblioteci partajate vor fi incluse în export, menținându-le "
"legătura." "legătura."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -491,7 +491,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"датотеке са дељеним библиотекама ће бити укључене у извоз, одржавајући " "Датотеке са дељеним библиотекама ће бити укључене у извоз, одржавајући "
"њихову повезаност." "њихову повезаност."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -582,7 +582,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"filer med delade bibliotek kommer att ingå i exporten, bibehåller deras " "Filer med delade bibliotek kommer att ingå i exporten, bibehåller deras "
"koppling." "koppling."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -583,7 +583,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"paylaşılan kütüphanelere sahip dosyalar, bağlantılarını koruyarak dışarı " "Paylaşılan kütüphanelere sahip dosyalar, bağlantılarını koruyarak dışarı "
"aktarmaya dahil edilecek." "aktarmaya dahil edilecek."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165

View File

@@ -577,7 +577,7 @@ msgstr ""
#: src/app/main/ui/exports/files.cljs:164 #: src/app/main/ui/exports/files.cljs:164
msgid "dashboard.export.options.all.message" msgid "dashboard.export.options.all.message"
msgstr "" msgstr ""
"файли з спільними бібліотеками буде додано до експорту зі збереженням " "Файли з спільними бібліотеками буде додано до експорту зі збереженням "
"зв'язків між ними." "зв'язків між ними."
#: src/app/main/ui/exports/files.cljs:165 #: src/app/main/ui/exports/files.cljs:165