Merge pull request #5404 from penpot/eva-fix-border-radius

♻️ Remove Rx and RY from shapes
This commit is contained in:
Andrey Antukh 2024-12-10 12:36:58 +01:00 committed by GitHub
commit 6f67ecd1e4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 364 additions and 458 deletions

View file

@ -522,8 +522,6 @@
:points
:x
:y
:rx
:ry
:r1
:r2
:r3

View file

@ -110,10 +110,6 @@
(add! :r3)
(add! :r4)))
(cond-> (and image? (some? (:rx shape)))
(-> (add! :rx)
(add! :ry)))
(cond-> path?
(-> (add! :stroke-cap-start)
(add! :stroke-cap-end)))

View file

@ -0,0 +1,123 @@
(ns app.main.ui.workspace.sidebar.options.menus.border-radius
(:require-macros [app.main.style :as stl])
(:require
[app.common.types.shape.radius :as ctsr]
[app.main.data.workspace.shapes :as dwsh]
[app.main.store :as st]
[app.main.ui.components.numeric-input :refer [numeric-input*]]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.foundations.assets.icon :refer [icon*]]
[app.util.i18n :as i18n :refer [tr]]
[rumext.v2 :as mf]))
(defn all-equal?
[shape]
(= (:r1 shape) (:r2 shape) (:r3 shape) (:r4 shape)))
(mf/defc border-radius-menu
{::mf/wrap-props false
::mf/wrap [mf/memo]}
[{:keys [ids ids-with-children values]}]
(let [all-equal? (all-equal? values)
radius-expanded* (mf/use-state false)
radius-expanded (deref radius-expanded*)
change-radius
(mf/use-fn
(mf/deps ids-with-children)
(fn [update-fn]
(dwsh/update-shapes ids-with-children
(fn [shape]
(if (ctsr/has-radius? shape)
(update-fn shape)
shape))
{:reg-objects? true
:attrs [:r1 :r2 :r3 :r4]})))
toggle-radius-mode
(mf/use-fn
(mf/deps radius-expanded)
(fn []
(swap! radius-expanded* not)))
on-single-radius-change
(mf/use-fn
(mf/deps ids change-radius)
(fn [value]
(let []
(st/emit!
(change-radius (fn [shape]
(ctsr/set-radius-to-all-corners shape value)))))))
on-radius-4-change
(mf/use-fn
(mf/deps ids change-radius)
(fn [value attr]
(st/emit! (change-radius #(ctsr/set-radius-to-single-corner % attr value)))))
on-radius-r1-change #(on-radius-4-change % :r1)
on-radius-r2-change #(on-radius-4-change % :r2)
on-radius-r3-change #(on-radius-4-change % :r3)
on-radius-r4-change #(on-radius-4-change % :r4)]
[:div {:class (stl/css :radius)}
(if (not radius-expanded)
[:div {:class (stl/css :radius-1)
:title (tr "workspace.options.radius")}
[:> icon* {:id "corner-radius"
:size "s"
:class (stl/css :icon)}]
[:> numeric-input*
{:placeholder (cond
(not all-equal?)
"Mixed"
(= :multiple (:r1 values))
(tr "settings.multiple")
:else
"--")
:min 0
:nillable true
:on-change on-single-radius-change
:value (if all-equal? (:r1 values) nil)}]]
[:div {:class (stl/css :radius-4)}
[:div {:class (stl/css :small-input)}
[:> numeric-input*
{:placeholder "--"
:title (tr "workspace.options.radius-top-left")
:min 0
:on-change on-radius-r1-change
:value (:r1 values)}]]
[:div {:class (stl/css :small-input)}
[:> numeric-input*
{:placeholder "--"
:title (tr "workspace.options.radius-top-right")
:min 0
:on-change on-radius-r2-change
:value (:r2 values)}]]
[:div {:class (stl/css :small-input)}
[:> numeric-input*
{:placeholder "--"
:title (tr "workspace.options.radius-bottom-left")
:min 0
:on-change on-radius-r4-change
:value (:r4 values)}]]
[:div {:class (stl/css :small-input)}
[:> numeric-input*
{:placeholder "--"
:title (tr "workspace.options.radius-bottom-right")
:min 0
:on-change on-radius-r3-change
:value (:r3 values)}]]])
[:> icon-button* {:class (stl/css-case :selected radius-expanded)
:variant "ghost"
:on-click toggle-radius-mode
:aria-label (tr "workspace.options.radius")
:title (if radius-expanded
(tr "workspace.options.radius.all-corners")
(tr "workspace.options.radius.single-corners"))
:icon "corner-radius"}]]))

View file

@ -0,0 +1,44 @@
// 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
@import "refactor/common-refactor.scss";
.radius {
display: flex;
align-items: flex-start;
justify-content: flex-start;
gap: $s-4;
}
.radius-1 {
@extend .input-element;
@include bodySmallTypography;
width: $s-108;
position: relative;
}
.radius-4 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: $s-4;
}
.small-input {
@extend .input-element;
@include bodySmallTypography;
width: $s-52;
margin-block-end: 0;
}
.selected {
border-color: var(--button-icon-border-color-selected);
background-color: var(--button-icon-background-color-selected);
color: var(--button-icon-foreground-color-selected);
}
.icon {
margin-inline: $s-4;
}

View file

@ -12,10 +12,8 @@
[app.common.logic.shapes :as cls]
[app.common.types.shape :as cts]
[app.common.types.shape.layout :as ctl]
[app.common.types.shape.radius :as ctsr]
[app.common.types.tokens-lib :as ctob]
[app.main.constants :refer [size-presets]]
[app.main.data.tokens :as dt]
[app.main.data.workspace :as udw]
[app.main.data.workspace.interactions :as dwi]
[app.main.data.workspace.shapes :as dwsh]
@ -28,6 +26,7 @@
[app.main.ui.context :as muc]
[app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i]
[app.main.ui.workspace.sidebar.options.menus.border-radius :refer [border-radius-menu]]
[app.main.ui.workspace.tokens.core :as wtc]
[app.main.ui.workspace.tokens.editable-select :refer [editable-select]]
[app.main.ui.workspace.tokens.style-dictionary :as sd]
@ -43,7 +42,6 @@
:x :y
:ox :oy
:rotation
:rx :ry
:r1 :r2 :r3 :r4
:selrect
:points
@ -111,13 +109,6 @@
(mf/deps tokens)
#(ctob/group-by-type tokens))
border-radius-tokens (:border-radius tokens-by-type)
border-radius-options (mf/use-memo
(mf/deps shape border-radius-tokens)
#(wtc/tokens->select-options
{:shape shape
:tokens border-radius-tokens
:attributes (wtty/token-attributes :border-radius)}))
sizing-tokens (:sizing tokens-by-type)
width-options (mf/use-memo
(mf/deps shape sizing-tokens)
@ -188,13 +179,6 @@
proportion-lock (:proportion-lock values)
radius-mode (ctsr/radius-mode values)
all-equal? (ctsr/all-equal? values)
radius-multi? (mf/use-state nil)
radius-input-ref (mf/use-ref nil)
clip-content-ref (mf/use-ref nil)
show-in-viewer-ref (mf/use-ref nil)
@ -298,89 +282,11 @@
(st/emit! (udw/trigger-bounding-box-cloaking ids)
(udw/increase-rotation ids value)))))
;; RADIUS
change-radius
(mf/use-fn
(mf/deps ids-with-children)
(fn [update-fn]
(dwsh/update-shapes ids-with-children
(fn [shape]
(if (ctsr/has-radius? shape)
(update-fn shape)
shape))
{:reg-objects? true
:attrs [:rx :ry :r1 :r2 :r3 :r4 :applied-tokens]})))
on-switch-to-radius-1
(mf/use-fn
(mf/deps ids change-radius)
(fn [_value]
(if all-equal?
(st/emit! (change-radius ctsr/switch-to-radius-1))
(reset! radius-multi? true))))
on-switch-to-radius-4
(mf/use-fn
(mf/deps ids change-radius)
(fn [_value]
(st/emit! (change-radius ctsr/switch-to-radius-4))
(reset! radius-multi? false)))
toggle-radius-mode
(mf/use-fn
(mf/deps radius-mode)
(fn []
(if (= :radius-1 radius-mode)
(on-switch-to-radius-4)
(on-switch-to-radius-1))))
on-border-radius-token-unapply
(mf/use-fn
(mf/deps ids change-radius)
(fn [token]
(let [token-value (wtc/maybe-resolve-token-value token)]
(st/emit!
(change-radius (fn [shape]
(-> (dt/unapply-token-id shape (wtty/token-attributes :border-radius))
(ctsr/set-radius-1 token-value))))))))
on-radius-1-change
(mf/use-fn
(mf/deps ids change-radius)
(fn [value]
(let [token-value (wtc/maybe-resolve-token-value value)]
(st/emit!
(change-radius (fn [shape]
(-> (dt/maybe-apply-token-to-shape {:token (when token-value value)
:shape shape
:attributes (wtty/token-attributes :border-radius)})
(ctsr/set-radius-1 (or token-value value)))))))))
on-radius-multi-change
(mf/use-fn
(mf/deps ids change-radius)
(fn [event]
(let [value (-> event dom/get-target dom/get-value d/parse-integer)]
(when (some? value)
(st/emit! (change-radius ctsr/switch-to-radius-1)
(change-radius #(ctsr/set-radius-1 % value)))
(reset! radius-multi? false)))))
on-radius-4-change
(mf/use-fn
(mf/deps ids change-radius)
(fn [value attr]
(st/emit! (change-radius #(ctsr/set-radius-4 % attr value)))))
on-width-change #(on-size-change % :width)
on-height-change #(on-size-change % :height)
on-pos-x-change #(on-position-change % :x)
on-pos-y-change #(on-position-change % :y)
on-radius-r1-change #(on-radius-4-change % :r1)
on-radius-r2-change #(on-radius-4-change % :r2)
on-radius-r3-change #(on-radius-4-change % :r3)
on-radius-r4-change #(on-radius-4-change % :r4)
;; CLIP CONTENT AND SHOW IN VIEWER
on-change-clip-content
@ -406,15 +312,6 @@
(st/emit! (dwu/commit-undo-transaction undo-id)))))]
(mf/use-layout-effect
(mf/deps radius-mode @radius-multi?)
(fn []
(when (and (= radius-mode :radius-1)
(= @radius-multi? false))
;; when going back from radius-multi to normal radius-1,
;; restore focus to the newly created numeric-input
(let [radius-input (mf/ref-val radius-input-ref)]
(dom/focus! radius-input)))))
[:div {:class (stl/css :element-set)}
(when (and (options :presets)
(or (nil? all-types) (= (count all-types) 1)))
@ -473,7 +370,7 @@
:class (stl/css :numeric-input)
:value (:width values)}]
[:& editable-select
{:placeholder (if (= :multiple (:rx values)) (tr "settings.multiple") "--")
{:placeholder (if (= :multiple (:r1 values)) (tr "settings.multiple") "--")
:class (stl/css :token-select)
:disabled disabled-width-sizing?
:on-change on-width-change
@ -497,7 +394,7 @@
:class (stl/css :numeric-input)
:value (:height values)}]
[:& editable-select
{:placeholder (if (= :multiple (:rx values)) (tr "settings.multiple") "--")
{:placeholder (if (= :multiple (:r1 values)) (tr "settings.multiple") "--")
:class (stl/css :token-select)
:disabled disabled-height-sizing?
:on-change on-height-change
@ -541,7 +438,6 @@
:value (:y values)}]]])
(when (or (options :rotation) (options :radius))
[:div {:class (stl/css :rotation-radius)}
(when (options :rotation)
[:div {:class (stl/css :rotation)
:title (tr "workspace.options.rotation")}
@ -555,91 +451,8 @@
:on-change on-rotation-change
:class (stl/css :numeric-input)
:value (:rotation values)}]])
(when (options :radius)
[:div {:class (stl/css :radius)}
[:div {:class (stl/css :radius-inputs)}
(cond
(= radius-mode :radius-1)
[:div {:class (stl/css :radius-1)
:title (tr "workspace.options.radius")}
[:span {:class (stl/css :icon)} i/corner-radius]
(if-not design-tokens?
[:> numeric-input*
{:placeholder (if (= :multiple (:rx values)) (tr "settings.multiple") "--")
:ref radius-input-ref
:min 0
:on-change on-radius-1-change
:class (stl/css :numeric-input)
:value (:rx values)}]
[:& editable-select
{:placeholder (if (= :multiple (:rx values)) (tr "settings.multiple") "--")
:class (stl/css :token-select)
:on-change on-radius-1-change
:on-token-remove on-border-radius-token-unapply
:options border-radius-options
:position :right
:value (:rx values)
:input-props {:type "number"
:min 0}}])]
@radius-multi?
[:div {:class (stl/css :radius-1)
:title (tr "workspace.options.radius")}
[:span {:class (stl/css :icon)} i/corner-radius]
[:input
{:type "number"
:placeholder "Mixed"
:min 0
:on-change on-radius-multi-change
:class (stl/css :numeric-input)
:value (if all-equal? (:rx values) nil)}]]
(= radius-mode :radius-4)
[:div {:class (stl/css :radius-4)}
[:div {:class (stl/css :small-input)
:title (tr "workspace.options.radius-top-left")}
[:> numeric-input*
{:placeholder "--"
:min 0
:on-change on-radius-r1-change
:class (stl/css :numeric-input)
:value (:r1 values)}]]
[:div {:class (stl/css :small-input)
:title (tr "workspace.options.radius-top-right")}
[:> numeric-input*
{:placeholder "--"
:min 0
:on-change on-radius-r2-change
:class (stl/css :numeric-input)
:value (:r2 values)}]]
[:div {:class (stl/css :small-input)
:title (tr "workspace.options.radius-bottom-left")}
[:> numeric-input*
{:placeholder "--"
:min 0
:on-change on-radius-r4-change
:class (stl/css :numeric-input)
:value (:r4 values)}]]
[:div {:class (stl/css :small-input)
:title (tr "workspace.options.radius-bottom-right")}
[:> numeric-input*
{:placeholder "--"
:min 0
:on-change on-radius-r3-change
:class (stl/css :numeric-input)
:value (:r3 values)}]]])]
[:button {:class (stl/css-case :radius-mode true
:selected (= radius-mode :radius-4))
:title (if (= radius-mode :radius-4)
(tr "workspace.options.radius.all-corners")
(tr "workspace.options.radius.single-corners"))
:on-click toggle-radius-mode}
i/corner-radius]])])
[:& border-radius-menu {:ids ids :ids-with-children ids-with-children :values values :shape shape}])])
(when (or (options :clip-content) (options :show-in-viewer))
[:div {:class (stl/css :clip-show)}
(when (options :clip-content)

View file

@ -172,48 +172,6 @@
padding-top: $s-1;
}
}
.radius {
display: flex;
align-items: flex-start;
justify-content: flex-start;
gap: $s-4;
}
.radius-inputs {
display: flex;
}
.radius-1 {
@extend .input-element;
@include bodySmallTypography;
width: $s-108;
position: relative;
}
.radius-4 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: $s-4;
.small-input {
@extend .input-element;
@include bodySmallTypography;
width: $s-52;
}
}
.radius-mode {
@extend .button-tertiary;
height: $s-32;
width: $s-28;
border-radius: $br-8;
svg {
@extend .button-icon;
stroke: var(--icon-foreground);
}
&.selected {
@extend .button-icon-selected;
}
}
.clip-show {
display: flex;

View file

@ -92,8 +92,8 @@
(defn update-shape-radius-all [value shape-ids]
(dwsh/update-shapes shape-ids
(fn [shape]
(when (ctsr/has-radius? shape)
(ctsr/set-radius-1 shape value)))
(when (ctsr/can-get-border-radius? shape)
(ctsr/set-radius-to-all-corners shape value)))
{:reg-objects? true
:attrs ctt/border-radius-keys}))
@ -112,12 +112,10 @@
(defn update-shape-radius-single-corner [value shape-ids attributes]
(dwsh/update-shapes shape-ids
(fn [shape]
(when (ctsr/has-radius? shape)
(cond-> shape
(:rx shape) (ctsr/switch-to-radius-4)
:always (ctsr/set-radius-4 (first attributes) value))))
(when (ctsr/can-get-border-radius? shape)
(ctsr/set-radius-to-single-corner shape (first attributes) value)))
{:reg-objects? true
:attrs [:rx :ry :r1 :r2 :r3 :r4]}))
:attrs ctt/border-radius-keys}))
(defn update-stroke-width
[value shape-ids]

View file

@ -17,8 +17,8 @@
(def filter-existing-values? false)
(def attributes->shape-update
{#{:rx :ry} (fn [v ids _] (wtch/update-shape-radius-all v ids))
#{:r1 :r2 :r3 :r4} wtch/update-shape-radius-single-corner
{#{:r1 :r2 :r3 :r4} wtch/update-shape-radius-single-corner
#_(fn [v ids _] (wtch/update-shape-radius-all v ids))
#{:fill} wtch/update-fill
#{:stroke-color} wtch/update-stroke-color
ctt/stroke-width-keys wtch/update-stroke-width
@ -70,11 +70,6 @@
(reduce
(fn [acc [attrs v]]
(cond
(some attrs #{:rx :ry}) (let [[_ a b] (data/diff #{:rx :ry} attrs)]
(cond-> (assoc acc b v)
;; Exact match in attrs
a (assoc a v)))
(some attrs #{:widht :height}) (let [[_ a b] (data/diff #{:width :height} attrs)]
(cond-> (assoc acc b v)
;; Exact match in attrs

View file

@ -313,11 +313,10 @@
:borderRadius
{:this true
:get #(-> % u/proxy->shape :rx)
:get #(-> % u/proxy->shape :r1)
:set
(fn [self value]
(let [id (obj/get self "$id")
shape (u/proxy->shape self)]
(let [id (obj/get self "$id")]
(cond
(or (not (us/safe-int? value)) (< value 0))
(u/display-not-valid :borderRadius value)
@ -325,21 +324,15 @@
(not (r/check-permission plugin-id "content:write"))
(u/display-not-valid :borderRadius "Plugin doesn't have 'content:write' permission")
(or (not (ctsr/has-radius? shape)) (ctsr/radius-4? shape))
(st/emit! (dwsh/update-shapes [id] #(-> %
ctsr/switch-to-radius-1
(ctsr/set-radius-1 value))))
:else
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-1 % value))))))}
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-to-all-corners % value))))))}
:borderRadiusTopLeft
{:this true
:get #(-> % u/proxy->shape :r1)
:set
(fn [self value]
(let [id (obj/get self "$id")
shape (u/proxy->shape self)]
(let [id (obj/get self "$id")]
(cond
(not (us/safe-int? value))
(u/display-not-valid :borderRadiusTopLeft value)
@ -347,21 +340,15 @@
(not (r/check-permission plugin-id "content:write"))
(u/display-not-valid :borderRadiusTopLeft "Plugin doesn't have 'content:write' permission")
(or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape)))
(st/emit! (dwsh/update-shapes [id] #(-> %
(ctsr/switch-to-radius-4)
(ctsr/set-radius-4 :r1 value))))
:else
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r1 value))))))}
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-to-single-corner % :r1 value))))))}
:borderRadiusTopRight
{:this true
:get #(-> % u/proxy->shape :r2)
:set
(fn [self value]
(let [id (obj/get self "$id")
shape (u/proxy->shape self)]
(let [id (obj/get self "$id")]
(cond
(not (us/safe-int? value))
(u/display-not-valid :borderRadiusTopRight value)
@ -369,21 +356,15 @@
(not (r/check-permission plugin-id "content:write"))
(u/display-not-valid :borderRadiusTopRight "Plugin doesn't have 'content:write' permission")
(or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape)))
(st/emit! (dwsh/update-shapes [id] #(-> %
(ctsr/switch-to-radius-4)
(ctsr/set-radius-4 :r2 value))))
:else
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r2 value))))))}
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-to-single-corner % :r2 value))))))}
:borderRadiusBottomRight
{:this true
:get #(-> % u/proxy->shape :r3)
:set
(fn [self value]
(let [id (obj/get self "$id")
shape (u/proxy->shape self)]
(let [id (obj/get self "$id")]
(cond
(not (us/safe-int? value))
(u/display-not-valid :borderRadiusBottomRight value)
@ -391,21 +372,15 @@
(not (r/check-permission plugin-id "content:write"))
(u/display-not-valid :borderRadiusBottomRight "Plugin doesn't have 'content:write' permission")
(or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape)))
(st/emit! (dwsh/update-shapes [id] #(-> %
(ctsr/switch-to-radius-4)
(ctsr/set-radius-4 :r3 value))))
:else
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r3 value))))))}
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-to-single-corner % :r3 value))))))}
:borderRadiusBottomLeft
{:this true
:get #(-> % u/proxy->shape :r4)
:set
(fn [self value]
(let [id (obj/get self "$id")
shape (u/proxy->shape self)]
(let [id (obj/get self "$id")]
(cond
(not (us/safe-int? value))
(u/display-not-valid :borderRadiusBottomLeft value)
@ -413,13 +388,8 @@
(not (r/check-permission plugin-id "content:write"))
(u/display-not-valid :borderRadiusBottomLeft "Plugin doesn't have 'content:write' permission")
(or (not (ctsr/has-radius? shape)) (not (ctsr/radius-4? shape)))
(st/emit! (dwsh/update-shapes [id] #(-> %
(ctsr/switch-to-radius-4)
(ctsr/set-radius-4 :r4 value))))
:else
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-4 % :r4 value))))))}
(st/emit! (dwsh/update-shapes [id] #(ctsr/set-radius-to-single-corner % :r4 value))))))}
:opacity
{:this true

View file

@ -541,16 +541,13 @@
r3 (get-meta node :r3 d/parse-double)
r4 (get-meta node :r4 d/parse-double)
rx (-> (get svg-data :rx 0) d/parse-double)
ry (-> (get svg-data :ry 0) d/parse-double)]
rx (-> (get svg-data :rx 0) d/parse-double)]
(cond-> props
(some? r1)
(assoc :r1 r1 :r2 r2 :r3 r3 :r4 r4
:rx nil :ry nil)
(assoc :r1 r1 :r2 r2 :r3 r3 :r4 r4)
(and (nil? r1) (some? rx))
(assoc :rx rx :ry ry))))
(assoc :r1 rx :r2 rx :r3 rx :r4 rx))))
(defn add-image-data
[props type node]