Compare commits

...

3 Commits

Author SHA1 Message Date
Eva Marco
ab095e8325 ♻️ Replace margin inputs 2026-01-26 13:24:22 +01:00
Eva Marco
77c6ba2fff Add test 2026-01-26 13:03:09 +01:00
Eva Marco
d51a2e9f1a Replace opacity numeric input 2026-01-26 13:03:09 +01:00
18 changed files with 653 additions and 233 deletions

View File

@@ -474,6 +474,8 @@
:height #{:sizing :dimensions}
:max-width #{:sizing :dimensions}
:max-height #{:sizing :dimensions}
:min-width #{:sizing :dimensions}
:min-height #{:sizing :dimensions}
:x #{:dimensions}
:y #{:dimensions}
:rotation #{:number :rotation}

View File

@@ -539,10 +539,11 @@
value shape-ids
#{:stroke-width}
page-id))
(some attributes #{:max-width :max-height})
(some attributes #{:max-width :max-height :layout-item-max-h :layout-item-max-w :layout-item-min-h :layout-item-min-w})
(conj #(update-layout-sizing-limits
value shape-ids
(set (filter attributes #{:max-width :max-height}))
(set (filter attributes #{:max-width :max-height :layout-item-max-h :layout-item-max-w :layout-item-min-h :layout-item-min-w}))
page-id))))
(defn apply-dimensions-token

View File

@@ -189,6 +189,7 @@
:float
:string
[:= :multiple]]]]
[:text-icon {:optional true} :string]
[:default {:optional true} [:maybe :string]]
[:placeholder {:optional true} :string]
[:icon {:optional true} [:maybe schema:icon]]
@@ -216,7 +217,8 @@
is-selected-on-focus nillable
tokens applied-token empty-to-end
on-change on-blur on-focus on-detach
property align ref name]
property align ref name
text-icon]
:rest props}]
(let [;; NOTE: we use mfu/bean here for transparently handle
@@ -637,14 +639,23 @@
:on-change store-raw-value
:variant "comfortable"
:disabled disabled
:slot-start (when icon
(mf/html [:> tooltip*
{:content property
:id property}
[:> icon* {:icon-id icon
:size "s"
:aria-labelledby property
:class (stl/css :icon)}]]))
:slot-start (when (or icon text-icon)
(mf/html
[:> tooltip*
{:content property
:id property}
(cond
icon
[:> icon*
{:icon-id icon
:size "s"
:aria-labelledby property
:class (stl/css :icon)}]
text-icon
[:div {:class (stl/css :text-icon)
:aria-labelledby property}
text-icon])]))
:slot-end (when-not disabled
(when (some? tokens)
(mf/html [:> icon-button* {:variant "ghost"
@@ -676,14 +687,23 @@
:disabled disabled
:on-blur on-blur
:class inner-class
:slot-start (when icon
(mf/html [:> tooltip*
{:content property
:id property}
[:> icon* {:icon-id icon
:size "s"
:aria-labelledby property
:class (stl/css :icon)}]]))
:slot-start (when (or icon text-icon)
(mf/html
[:> tooltip*
{:content property
:id property}
(cond
icon
[:> icon*
{:icon-id icon
:size "s"
:aria-labelledby property
:class (stl/css :icon)}]
text-icon
[:div {:class (stl/css :text-icon)
:aria-labelledby property}
text-icon])]))
:token-wrapper-ref token-wrapper-ref
:token-detach-btn-ref token-detach-btn-ref
:detach-token detach-token})))]
@@ -718,21 +738,41 @@
(mf/with-effect [dropdown-options]
(mf/set-ref-val! options-ref dropdown-options))
[:div {:class (dm/str class " " (stl/css :input-wrapper))
:ref wrapper-ref}
(if (some? icon)
[:div {:class (dm/str class " " (stl/css :input-wrapper))
:ref wrapper-ref}
(if (and (some? token-applied)
(not= :multiple token-applied))
[:> token-field* token-props]
[:> input-field* input-props])
(if (and (some? token-applied)
(not= :multiple token-applied))
[:> token-field* token-props]
[:> input-field* input-props])
(when ^boolean is-open
(let [options (if (delay? dropdown-options) @dropdown-options dropdown-options)]
[:> options-dropdown* {:on-click on-option-click
:id listbox-id
:options options
:selected selected-id
:focused focused-id
:align align
:empty-to-end empty-to-end
:ref set-option-ref}]))]))
(when ^boolean is-open
(let [options (if (delay? dropdown-options) @dropdown-options dropdown-options)]
[:> options-dropdown* {:on-click on-option-click
:id listbox-id
:options options
:selected selected-id
:focused focused-id
:align align
:empty-to-end empty-to-end
:ref set-option-ref}]))]
[:div {:class (dm/str class " " (stl/css :input-wrapper))
:aria-labelledby property
:ref wrapper-ref}
(if (and (some? token-applied)
(not= :multiple token-applied))
[:> token-field* token-props]
[:> input-field* input-props])
(when ^boolean is-open
(let [options (if (delay? dropdown-options) @dropdown-options dropdown-options)]
[:> options-dropdown* {:on-click on-option-click
:id listbox-id
:options options
:selected selected-id
:focused focused-id
:align align
:empty-to-end empty-to-end
:ref set-option-ref}]))])))

View File

@@ -32,6 +32,14 @@
min-width: var(--sp-l);
}
.text-icon {
color: var(--color-foreground-secondary);
@include t.use-typography("code-font");
width: fit-content;
// TODO: Review
min-width: 40px;
}
.invisible-button {
position: absolute;
inset-inline-end: 0;

View File

@@ -17,7 +17,7 @@
--token-field-outline-color: none;
--token-field-height: var(--sp-xxxl);
--token-field-margin: unset;
display: grid;
display: inline-flex;
column-gap: var(--sp-xs);
align-items: center;
position: relative;

View File

@@ -9,13 +9,18 @@
(:require
[app.common.data :as d]
[app.common.types.shape.layout :as ctl]
[app.common.types.token :as tk]
[app.main.data.workspace :as udw]
[app.main.data.workspace.shape-layout :as dwsl]
[app.main.data.workspace.tokens.application :as dwta]
[app.main.features :as features]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.numeric-input :as deprecated-input]
[app.main.ui.components.title-bar :refer [title-bar*]]
[app.main.ui.context :as muc]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.controls.numeric-input :refer [numeric-input*]]
[app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]]
[app.main.ui.ds.foundations.assets.icon :as i]
[app.main.ui.icons :as deprecated-icon]
@@ -24,6 +29,51 @@
[app.util.i18n :as i18n :refer [tr]]
[rumext.v2 :as mf]))
(mf/defc numeric-input-wrapper*
{::mf/private true}
[{:keys [values name applied-tokens align on-detach placeholder] :rest props}]
(let [tokens (mf/use-ctx muc/active-tokens-by-type)
input-type (cond
(some #{:m2 :m4} [name])
:horizontal-margin
(some #{:m1 :m3} [name])
:vertical-margin
(= name :layout-item-max-w)
:max-width
(= name :layout-item-max-h)
:max-height
(= name :layout-item-min-w)
:min-width
(= name :layout-item-min-h)
:min-height
:else
name)
tokens (mf/with-memo [tokens input-type]
(delay
(-> (deref tokens)
(select-keys (get tk/tokens-by-input input-type))
(not-empty))))
on-detach-attr
(mf/use-fn
(mf/deps on-detach name)
#(on-detach % name))
props (mf/spread-props props
{:placeholder (or placeholder "--")
:applied-token (get applied-tokens name)
:tokens tokens
:align align
:on-detach on-detach-attr
:value (get values name)})]
[:> numeric-input* props]))
(def layout-item-attrs
[:layout-item-margin ;; {:m1 0 :m2 0 :m3 0 :m4 0}
:layout-item-margin-type ;; :simple :multiple
@@ -46,147 +96,325 @@
(select-margins (= prop :m1) (= prop :m2) (= prop :m3) (= prop :m4)))
(mf/defc margin-simple*
[{:keys [value on-change on-blur]}]
(let [m1 (:m1 value)
[{:keys [value on-change on-blur applied-tokens ids]}]
(let [token-numeric-inputs
(features/use-feature "tokens/numeric-input")
m1 (:m1 value)
m2 (:m2 value)
m3 (:m3 value)
m4 (:m4 value)
m1-placeholder (if (and (not= value :multiple) (not= m1 m3)) (tr "settings.multiple") "--")
m2-placeholder (if (and (not= value :multiple) (not= m2 m4)) (tr "settings.multiple") "--")
m1 (when (and (not= value :multiple) (= m1 m3)) m1)
m2 (when (and (not= value :multiple) (= m2 m4)) m2)
token-applied-m1 (:m1 applied-tokens)
token-applied-m2 (:m2 applied-tokens)
token-applied-m3 (:m3 applied-tokens)
token-applied-m4 (:m4 applied-tokens)
token-applied-m1 (if (and (not= applied-tokens :multiple) (= token-applied-m1 token-applied-m3)) token-applied-m1
:multiple)
token-applied-m2 (if (and (not= applied-tokens :multiple) (= token-applied-m2 token-applied-m4)) token-applied-m2
:multiple)
m1-placeholder (if (and (not= value :multiple)
(= m1 m3)
(= token-applied-m1 token-applied-m3))
"--"
(tr "settings.multiple"))
m2-placeholder (if (and (not= value :multiple)
(= m2 m4)
(= token-applied-m2 token-applied-m4))
"--"
(tr "settings.multiple"))
on-focus
(mf/use-fn
(fn [event]
(let [attr (-> (dom/get-current-target event)
(dom/get-data "name")
(keyword))]
(case attr
:m1 (select-margins true false true false)
:m2 (select-margins false true false true))
(dom/select-target event))))
(fn [attr event]
(case attr
:m1 (select-margins true false true false)
:m2 (select-margins false true false true))
(dom/select-target event)))
on-detach-token
(mf/use-fn
(mf/deps ids)
(fn [token attr]
(st/emit! (dwta/unapply-token {:token (first token)
:attributes #{attr}
:shape-ids ids}))))
on-change'
(mf/use-fn
(mf/deps on-change)
(fn [value event]
(let [attr (-> (dom/get-current-target event)
(dom/get-data "name")
(keyword))]
(on-change :simple attr value))))]
(mf/deps on-change ids)
(fn [value attr]
(if (or (string? value) (int? value))
(on-change :simple attr value)
(do
(st/emit!
(dwta/toggle-token {:token (first value)
:attrs (if (= :m1 attr)
#{:m1 :m3}
#{:m2 :m4})
:shape-ids ids}))))))
on-focus-m1
(mf/use-fn (mf/deps on-focus) #(on-focus :m1))
on-focus-m2
(mf/use-fn (mf/deps on-focus) #(on-focus :m2))
on-m1-change
(mf/use-fn (mf/deps on-change') #(on-change' % :m1))
on-m2-change
(mf/use-fn (mf/deps on-change') #(on-change' % :m2))]
[:div {:class (stl/css :margin-simple)}
[:div {:class (stl/css :vertical-margin)
:title "Vertical margin"}
[:span {:class (stl/css :icon)}
deprecated-icon/margin-top-bottom]
[:> deprecated-input/numeric-input* {:class (stl/css :numeric-input)
:placeholder m1-placeholder
:data-name "m1"
:on-focus on-focus
:on-change on-change'
:on-blur on-blur
:nillable true
:value m1}]]
(if token-numeric-inputs
[:> numeric-input-wrapper*
{:on-change on-m1-change
:on-detach on-detach-token
:class (stl/css :vertical-margin-wrapper)
:on-blur on-blur
:on-focus on-focus-m1
:placeholder m1-placeholder
:icon i/margin-top-bottom
:min 0
:name :m1
:property "Vertical margin "
:nillable true
:applied-tokens {:m1 token-applied-m1}
:values {:m1 m1}}]
[:div {:class (stl/css :horizontal-margin)
:title "Horizontal margin"}
[:span {:class (stl/css :icon)}
deprecated-icon/margin-left-right]
[:> deprecated-input/numeric-input* {:class (stl/css :numeric-input)
:placeholder m2-placeholder
:data-name "m2"
:on-focus on-focus
:on-change on-change'
:on-blur on-blur
:nillable true
:value m2}]]]))
[:div {:class (stl/css :vertical-margin)
:title "Vertical margin"}
[:span {:class (stl/css :icon)}
deprecated-icon/margin-top-bottom]
[:> deprecated-input/numeric-input* {:class (stl/css :numeric-input)
:placeholder m1-placeholder
:data-name "m1"
:on-focus on-focus-m1
:on-change on-m1-change
:on-blur on-blur
:nillable true
:value m1}]])
(if token-numeric-inputs
[:> numeric-input-wrapper*
{:on-change on-m2-change
:on-detach on-detach-token
:on-blur on-blur
:on-focus on-focus-m2
:placeholder m2-placeholder
:icon i/margin-left-right
:class (stl/css :horizontal-margin-wrapper)
:min 0
:name :m2
:align :right
:property "Horizontal margin"
:nillable true
:applied-tokens {:m2 token-applied-m2}
:values {:m2 m2}}]
[:div {:class (stl/css :horizontal-margin)
:title "Horizontal margin"}
[:span {:class (stl/css :icon)}
deprecated-icon/margin-left-right]
[:> deprecated-input/numeric-input* {:class (stl/css :numeric-input)
:placeholder m2-placeholder
:data-name "m2"
:on-focus on-focus-m2
:on-change on-m2-change
:on-blur on-blur
:nillable true
:value m2}]])]))
(mf/defc margin-multiple*
[{:keys [value on-change on-blur]}]
(let [m1 (:m1 value)
[{:keys [value on-change on-blur applied-tokens ids]}]
(let [token-numeric-inputs
(features/use-feature "tokens/numeric-input")
m1 (:m1 value)
m2 (:m2 value)
m3 (:m3 value)
m4 (:m4 value)
applied-token-to-m1 (:m1 applied-tokens)
applied-token-to-m2 (:m2 applied-tokens)
applied-token-to-m3 (:m3 applied-tokens)
applied-token-to-m4 (:m4 applied-tokens)
on-detach-token
(mf/use-fn
(mf/deps ids)
(fn [token attr]
(st/emit! (dwta/unapply-token {:token (first token)
:attributes #{attr}
:shape-ids ids}))))
on-focus
(mf/use-fn
(fn [event]
(let [attr (-> (dom/get-current-target event)
(dom/get-data "name")
(keyword))]
(select-margin attr)
(dom/select-target event))))
(fn [attr event]
(select-margin attr)
(dom/select-target event)))
on-focus-m1
(mf/use-fn (mf/deps on-focus) #(on-focus :m1))
on-focus-m2
(mf/use-fn (mf/deps on-focus) #(on-focus :m2))
on-focus-m3
(mf/use-fn (mf/deps on-focus) #(on-focus :m1))
on-focus-m4
(mf/use-fn (mf/deps on-focus) #(on-focus :m2))
on-change'
(mf/use-fn
(mf/deps on-change)
(fn [value event]
(let [attr (-> (dom/get-current-target event)
(dom/get-data "name")
(keyword))]
(on-change :multiple attr value))))]
(mf/deps on-change ids)
(fn [value attr]
(if (or (string? value) (int? value))
(on-change :multiple attr value)
(do
(st/emit!
(dwta/toggle-token {:token (first value)
:attrs #{attr}
:shape-ids ids}))))))
on-m1-change
(mf/use-fn (mf/deps on-change') #(on-change' % :m1))
on-m2-change
(mf/use-fn (mf/deps on-change') #(on-change' % :m2))
on-m3-change
(mf/use-fn (mf/deps on-change') #(on-change' % :m3))
on-m4-change
(mf/use-fn (mf/deps on-change') #(on-change' % :m4))]
[:div {:class (stl/css :margin-multiple)}
[:div {:class (stl/css :top-margin)
:title "Top margin"}
[:span {:class (stl/css :icon)}
deprecated-icon/margin-top]
[:> deprecated-input/numeric-input* {:class (stl/css :numeric-input)
:placeholder "--"
:data-name "m1"
:on-focus on-focus
:on-change on-change'
:on-blur on-blur
:nillable true
:value m1}]]
[:div {:class (stl/css :right-margin)
:title "Right margin"}
[:span {:class (stl/css :icon)}
deprecated-icon/margin-right]
[:> deprecated-input/numeric-input* {:class (stl/css :numeric-input)
:placeholder "--"
:data-name "m2"
:on-focus on-focus
:on-change on-change'
:on-blur on-blur
:nillable true
:value m2}]]
(if token-numeric-inputs
[:> numeric-input-wrapper*
{:on-change on-m1-change
:on-detach on-detach-token
:on-blur on-blur
:on-focus on-focus-m1
:icon i/margin-top
:class (stl/css :top-margin-wrapper)
:min 0
:name :m1
:property "Top margin"
:nillable true
:applied-tokens {:m1 applied-token-to-m1}
:values {:m1 m1}}]
[:div {:class (stl/css :bottom-margin)
:title "Bottom margin"}
[:span {:class (stl/css :icon)}
deprecated-icon/margin-bottom]
[:> deprecated-input/numeric-input* {:class (stl/css :numeric-input)
:placeholder "--"
:data-name "m3"
:on-focus on-focus
:on-change on-change'
:on-blur on-blur
:nillable true
:value m3}]]
[:div {:class (stl/css :top-margin)
:title "Top margin"}
[:span {:class (stl/css :icon)}
deprecated-icon/margin-top]
[:> deprecated-input/numeric-input* {:class (stl/css :numeric-input)
:placeholder "--"
:data-name "m1"
:on-focus on-focus-m1
:on-change on-m1-change
:on-blur on-blur
:nillable true
:value m1}]])
(if token-numeric-inputs
[:> numeric-input-wrapper*
{:on-change on-m2-change
:on-detach on-detach-token
:on-blur on-blur
:on-focus on-focus-m2
:icon i/margin-right
:class (stl/css :right-margin-wrapper)
:min 0
:name :m2
:align :right
:property "Right margin"
:nillable true
:applied-tokens {:m2 applied-token-to-m2}
:values {:m2 m2}}]
[:div {:class (stl/css :left-margin)
:title "Left margin"}
[:span {:class (stl/css :icon)}
deprecated-icon/margin-left]
[:> deprecated-input/numeric-input* {:class (stl/css :numeric-input)
:placeholder "--"
:data-name "m4"
:on-focus on-focus
:on-change on-change'
:on-blur on-blur
:nillable true
:value m4}]]]))
[:div {:class (stl/css :right-margin)
:title "Right margin"}
[:span {:class (stl/css :icon)}
deprecated-icon/margin-right]
[:> deprecated-input/numeric-input* {:class (stl/css :numeric-input)
:placeholder "--"
:data-name "m2"
:on-focus on-focus-m2
:on-change on-m2-change
:on-blur on-blur
:nillable true
:value m2}]])
(if token-numeric-inputs
[:> numeric-input-wrapper*
{:on-change on-m3-change
:on-detach on-detach-token
:on-blur on-blur
:on-focus on-focus-m3
:icon i/margin-bottom
:class (stl/css :bottom-margin-wrapper)
:min 0
:name :m3
:align :right
:property "Bottom margin"
:nillable true
:applied-tokens {:m3 applied-token-to-m3}
:values {:m3 m3}}]
[:div {:class (stl/css :bottom-margin)
:title "Bottom margin"}
[:span {:class (stl/css :icon)}
deprecated-icon/margin-bottom]
[:> deprecated-input/numeric-input* {:class (stl/css :numeric-input)
:placeholder "--"
:data-name "m3"
:on-focus on-focus-m3
:on-change on-m3-change
:on-blur on-blur
:nillable true
:value m3}]])
(if token-numeric-inputs
[:> numeric-input-wrapper*
{:on-change on-m4-change
:on-detach on-detach-token
:on-blur on-blur
:on-focus on-focus-m4
:icon i/margin-left
:class (stl/css :left-margin-wrapper)
:min 0
:name :m4
:property "Left margin"
:nillable true
:applied-tokens {:m4 applied-token-to-m4}
:values {:m4 m4}}]
[:div {:class (stl/css :left-margin)
:title "Left margin"}
[:span {:class (stl/css :icon)}
deprecated-icon/margin-left]
[:> deprecated-input/numeric-input* {:class (stl/css :numeric-input)
:placeholder "--"
:data-name "m4"
:on-focus on-focus-m4
:on-change on-m4-change
:on-blur on-blur
:nillable true
:value m4}]])]))
(mf/defc margin-section*
{::mf/private true
::mf/expect-props #{:value :type :on-type-change :on-change}}
::mf/expect-props #{:value :type :on-type-change :on-change :applied-tokens :ids}}
[{:keys [type on-type-change] :as props}]
(let [type (d/nilv type :simple)
on-blur (mf/use-fn #(select-margins false false false false))
@@ -292,8 +520,187 @@
:label "Align self end"
:value "end"}]}])
(mf/defc layout-size-constraints*
{::mf/private true
::mf/expect-props #{:value :applied-tokens :ids :v-sizing}}
[{:keys [values v-sizing ids applied-tokens] :as props}]
(let [token-numeric-inputs
(features/use-feature "tokens/numeric-input")
min-w (get values :layout-item-min-w)
max-w (get values :layout-item-max-w)
min-h (get values :layout-item-min-h)
max-h (get values :layout-item-max-h)
applied-token-to-min-w (get applied-tokens :layout-item-min-w)
applied-token-to-max-w (get applied-tokens :layout-item-max-w)
applied-token-to-min-h (get applied-tokens :layout-item-min-h)
applied-token-to-max-h (get applied-tokens :layout-item-max-h)
on-detach-token
(mf/use-fn
(mf/deps ids)
(fn [token attr]
(st/emit! (dwta/unapply-token {:token (first token)
:attributes #{attr}
:shape-ids ids}))))
on-size-change
(mf/use-fn
(mf/deps ids)
(fn [value attr]
(if (or (string? value) (int? value))
(st/emit! (dwsl/update-layout-child ids {attr value}))
(do
(st/emit!
(dwta/toggle-token {:token (first value)
:attrs #{attr}
:shape-ids ids}))))))
on-layout-item-min-w-change
(mf/use-fn (mf/deps on-size-change) #(on-size-change % :layout-item-min-w))
on-layout-item-max-w-change
(mf/use-fn (mf/deps on-size-change) #(on-size-change % :layout-item-max-w))
on-layout-item-min-h-change
(mf/use-fn (mf/deps on-size-change) #(on-size-change % :layout-item-min-h))
on-layout-item-max-h-change
(mf/use-fn (mf/deps on-size-change) #(on-size-change % :layout-item-max-h))]
[:div {:class (stl/css :advanced-options)}
(when (= (:layout-item-h-sizing values) :fill)
[:div {:class (stl/css :horizontal-fill)}
(if token-numeric-inputs
[:> numeric-input-wrapper*
{:on-change on-layout-item-min-w-change
:on-detach on-detach-token
:class (stl/css :min-w-wrapper)
:min 0
:name :layout-item-min-w
:property (tr "workspace.options.layout-item.layout-item-min-w")
:text-icon "MIN W"
:nillable true
:applied-tokens {:layout-item-min-w applied-token-to-min-w}
:tooltip-class (stl/css :tooltip-wrapper)
:values {:layout-item-min-w min-w}}]
[:div {:class (stl/css :layout-item-min-w)
:title (tr "workspace.options.layout-item.layout-item-min-w")}
[:span {:class (stl/css :icon-text)} "MIN W"]
[:> deprecated-input/numeric-input*
{:class (stl/css :numeric-input)
:no-validate true
:min 0
:data-wrap true
:placeholder "--"
:data-attr "layout-item-min-w"
:on-focus dom/select-target
:on-change on-layout-item-min-w-change
:value (get values :layout-item-min-w)
:nillable true}]])
(if token-numeric-inputs
[:> numeric-input-wrapper*
{:on-change on-layout-item-max-w-change
:on-detach on-detach-token
:text-icon "MAX W"
:class (stl/css :max-w-wrapper)
:min 0
:name :layout-item-max-w
:property (tr "workspace.options.layout-item.layout-item-max-w")
:nillable true
:tooltip-class (stl/css :tooltip-wrapper)
:applied-tokens {:layout-item-max-w applied-token-to-max-w}
:values {:layout-item-max-w max-w}}]
[:div {:class (stl/css :layout-item-max-w)
:title (tr "workspace.options.layout-item.layout-item-max-w")}
[:span {:class (stl/css :icon-text)} "MAX W"]
[:> deprecated-input/numeric-input*
{:class (stl/css :numeric-input)
:no-validate true
:min 0
:data-wrap true
:placeholder "--"
:data-attr "layout-item-max-w"
:on-focus dom/select-target
:on-change on-layout-item-max-w-change
:value (get values :layout-item-max-w)
:nillable true}]])])
(when (= v-sizing :fill)
[:div {:class (stl/css :vertical-fill)}
(if token-numeric-inputs
[:> numeric-input-wrapper*
{:on-change on-layout-item-min-h-change
:on-detach on-detach-token
:text-icon "MIN H"
:class (stl/css :min-h-wrapper)
:min 0
:name :layout-item-min-h
:property (tr "workspace.options.layout-item.layout-item-min-h")
:nillable true
:tooltip-class (stl/css :tooltip-wrapper)
:applied-tokens {:layout-item-min-h applied-token-to-min-h}
:values {:layout-item-min-h min-h}}]
[:div {:class (stl/css :layout-item-min-h)
:title (tr "workspace.options.layout-item.layout-item-min-h")}
[:span {:class (stl/css :icon-text)} "MIN H"]
[:> deprecated-input/numeric-input*
{:class (stl/css :numeric-input)
:no-validate true
:min 0
:data-wrap true
:placeholder "--"
:data-attr "layout-item-min-h"
:on-focus dom/select-target
:on-change on-layout-item-min-h-change
:value (get values :layout-item-min-h)
:nillable true}]])
(if token-numeric-inputs
[:> numeric-input-wrapper*
{:on-change on-layout-item-max-h-change
:on-detach on-detach-token
:class (stl/css :max-h-wrapper)
:min 0
:text-icon "MAX H"
:name :layout-item-max-h
:property (tr "workspace.options.layout-item.layout-item-max-h")
:nillable true
:tooltip-class (stl/css :tooltip-wrapper)
:applied-tokens {:layout-item-max-h applied-token-to-max-h}
:values {:layout-item-max-h max-h}}]
[:div {:class (stl/css :layout-item-max-h)
:title (tr "workspace.options.layout-item.layout-item-max-h")}
[:span {:class (stl/css :icon-text)} "MAX H"]
[:> deprecated-input/numeric-input*
{:class (stl/css :numeric-input)
:no-validate true
:min 0
:data-wrap true
:placeholder "--"
:data-attr "layout-item-max-h"
:on-focus dom/select-target
:on-change on-layout-item-max-h-change
:value (get values :layout-item-max-h)
:nillable true}]])])]))
(mf/defc layout-item-menu
{::mf/memo #{:ids :values :type :is-layout-child? :is-grid-parent :is-flex-parent? :is-grid-layout? :is-flex-layout?}
{::mf/memo #{:ids :values :type :is-layout-child? :is-grid-parent :is-flex-parent? :is-grid-layout? :is-flex-layout? :applied-tokens}
::mf/props :obj}
[{:keys [ids values
^boolean is-layout-child?
@@ -301,7 +708,8 @@
^boolean is-grid-parent?
^boolean is-flex-parent?
^boolean is-flex-layout?
^boolean is-grid-layout?]}]
^boolean is-grid-layout?
applied-tokens]}]
(let [selection-parents* (mf/use-memo (mf/deps ids) #(refs/parents-by-ids ids))
selection-parents (mf/deref selection-parents*)
@@ -397,16 +805,7 @@
(fn [value]
(st/emit! (dwsl/update-layout-child ids {:layout-item-v-sizing (keyword value)}))))
;; Size and position
on-size-change
(mf/use-fn
(mf/deps ids)
(fn [value event]
(let [attr (-> (dom/get-current-target event)
(dom/get-data "attr")
(keyword))]
(st/emit! (dwsl/update-layout-child ids {attr value})))))
;; Position
on-change-position
(mf/use-fn
(mf/deps ids)
@@ -483,74 +882,13 @@
[:> margin-section* {:value (:layout-item-margin values)
:type (:layout-item-margin-type values)
:on-type-change on-margin-type-change
:applied-tokens applied-tokens
:ids ids
:on-change on-margin-change}])
(when (or (= h-sizing :fill)
(= v-sizing :fill))
[:div {:class (stl/css :advanced-options)}
(when (= (:layout-item-h-sizing values) :fill)
[:div {:class (stl/css :horizontal-fill)}
[:div {:class (stl/css :layout-item-min-w)
:title (tr "workspace.options.layout-item.layout-item-min-w")}
[:span {:class (stl/css :icon-text)} "MIN W"]
[:> deprecated-input/numeric-input*
{:class (stl/css :numeric-input)
:no-validate true
:min 0
:data-wrap true
:placeholder "--"
:data-attr "layout-item-min-w"
:on-focus dom/select-target
:on-change on-size-change
:value (get values :layout-item-min-w)
:nillable true}]]
[:div {:class (stl/css :layout-item-max-w)
:title (tr "workspace.options.layout-item.layout-item-max-w")}
[:span {:class (stl/css :icon-text)} "MAX W"]
[:> deprecated-input/numeric-input*
{:class (stl/css :numeric-input)
:no-validate true
:min 0
:data-wrap true
:placeholder "--"
:data-attr "layout-item-max-w"
:on-focus dom/select-target
:on-change on-size-change
:value (get values :layout-item-max-w)
:nillable true}]]])
(when (= v-sizing :fill)
[:div {:class (stl/css :vertical-fill)}
[:div {:class (stl/css :layout-item-min-h)
:title (tr "workspace.options.layout-item.layout-item-min-h")}
[:span {:class (stl/css :icon-text)} "MIN H"]
[:> deprecated-input/numeric-input*
{:class (stl/css :numeric-input)
:no-validate true
:min 0
:data-wrap true
:placeholder "--"
:data-attr "layout-item-min-h"
:on-focus dom/select-target
:on-change on-size-change
:value (get values :layout-item-min-h)
:nillable true}]]
[:div {:class (stl/css :layout-item-max-h)
:title (tr "workspace.options.layout-item.layout-item-max-h")}
[:span {:class (stl/css :icon-text)} "MAX H"]
[:> deprecated-input/numeric-input*
{:class (stl/css :numeric-input)
:no-validate true
:min 0
:data-wrap true
:placeholder "--"
:data-attr "layout-item-max-h"
:on-focus dom/select-target
:on-change on-size-change
:value (get values :layout-item-max-h)
:nillable true}]]])])])]))
[:> layout-size-constraints* {:ids ids
:values values
:applied-tokens applied-tokens
:v-sizing v-sizing}])])]))

View File

@@ -85,6 +85,16 @@
}
}
.vertical-margin-wrapper {
grid-column: 1;
--dropdown-width: var(--7-columns-dropdown-width);
}
.horizontal-margin-wrapper {
grid-column: 2;
--dropdown-width: var(--7-columns-dropdown-width);
}
.margin-multiple {
display: grid;
grid-template-columns: subgrid;
@@ -99,22 +109,30 @@
@include deprecated.bodySmallTypography;
}
.top-margin {
.top-margin,
.top-margin-wrapper {
--dropdown-width: var(--7-columns-dropdown-width);
grid-column: 1;
grid-row: 1;
}
.bottom-margin {
.bottom-margin,
.bottom-margin-wrapper {
--dropdown-width: var(--7-columns-dropdown-width);
grid-column: 2;
grid-row: 1;
}
.left-margin {
.left-margin,
.left-margin-wrapper {
--dropdown-width: var(--7-columns-dropdown-width);
grid-column: 1;
grid-row: 2;
}
.right-margin {
.right-margin,
.right-margin-wrapper {
--dropdown-width: var(--7-columns-dropdown-width);
grid-column: 2;
grid-row: 2;
}
@@ -151,3 +169,7 @@
.inputs-wrapper {
grid-column: 1 / span 2;
}
.tooltip-wrapper {
inline-size: 100%;
}

View File

@@ -114,6 +114,7 @@
:is-layout-child? true
:is-flex-parent? is-flex-parent?
:is-grid-parent? is-grid-parent?
:applied-tokens applied-tokens
:shape shape}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)

View File

@@ -113,6 +113,7 @@
:is-layout-container? false
:is-flex-parent? is-flex-parent?
:is-grid-parent? is-grid-parent?
:applied-tokens applied-tokens
:shape shape}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)

View File

@@ -135,6 +135,7 @@
:is-flex-layout? is-flex-layout?
:is-grid-layout? is-grid-layout?
:is-layout-child? is-layout-child?
:applied-tokens applied-tokens
:is-layout-container? is-layout-container?
:shape shape}])

View File

@@ -139,6 +139,7 @@
:is-layout-container? false
:is-flex-parent? is-flex-parent?
:is-grid-parent? is-grid-parent?
:applied-tokens applied-tokens
:values layout-item-values}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)

View File

@@ -409,7 +409,7 @@
[layout-container-ids layout-container-values layout-container-tokens]
(get-attrs shapes objects :layout-container)
[layout-item-ids layout-item-values {}]
[layout-item-ids layout-item-values layout-item-tokens]
(get-attrs shapes objects :layout-item)
components
@@ -471,6 +471,7 @@
:is-layout-container? all-flex-layout-container?
:is-flex-parent? is-flex-parent?
:is-grid-parent? is-grid-parent?
:applied-tokens layout-item-tokens
:values layout-item-values}])
(when-not (or (empty? constraint-ids) ^boolean is-layout-child?)

View File

@@ -113,6 +113,7 @@
:is-layout-container? false
:is-flex-parent? is-flex-parent?
:is-grid-parent? is-grid-parent?
:applied-tokens applied-tokens
:shape shape}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)

View File

@@ -112,6 +112,7 @@
:values layout-item-values
:is-layout-child? true
:is-flex-parent? is-flex-parent?
:applied-tokens applied-tokens
:is-grid-parent? is-grid-parent?
:shape shape}])

View File

@@ -180,6 +180,7 @@
:is-layout-child? true
:is-flex-parent? is-flex-parent?
:is-grid-parent? is-grid-parent?
:applied-tokens applied-tokens
:shape shape}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)

View File

@@ -154,6 +154,7 @@
:is-layout-child? true
:is-flex-parent? is-flex-parent?
:is-grid-parent? is-grid-parent?
:applied-tokens applied-tokens
:shape shape}])
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)

View File

@@ -6713,19 +6713,19 @@ msgstr "Advanced options"
#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:543
msgid "workspace.options.layout-item.layout-item-max-h"
msgstr "Max.Height"
msgstr "Max height"
#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:510
msgid "workspace.options.layout-item.layout-item-max-w"
msgstr "Max.Width"
msgstr "Max width"
#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:527
msgid "workspace.options.layout-item.layout-item-min-h"
msgstr "Min.Height"
msgstr "Min height"
#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs:494
msgid "workspace.options.layout-item.layout-item-min-w"
msgstr "Min.Width"
msgstr "Min width"
#: src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs
#, unused

View File

@@ -7164,11 +7164,11 @@ msgstr "Ancho"
#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:535, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:552
msgid "workspace.options.x"
msgstr "eje X"
msgstr "Eje X"
#: src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:545, src/app/main/ui/workspace/sidebar/options/menus/measures.cljs:563
msgid "workspace.options.y"
msgstr "eje Y"
msgstr "Eje Y"
#: src/app/main/ui/workspace/viewport/path_actions.cljs:140
msgid "workspace.path.actions.add-node"