From d7d2d36e0ab4146623e63036d82b39d7f9f5c94f Mon Sep 17 00:00:00 2001 From: Eva Marco Date: Wed, 10 Sep 2025 13:03:13 +0200 Subject: [PATCH] :recycle: Replace measure inputs for numeric input component --- common/src/app/common/features.cljc | 4 + common/src/app/common/types/token.cljc | 2 +- .../data/workspace/tokens/application.cljs | 141 +--------- frontend/src/app/main/ui/context.cljs | 1 + .../main/ui/ds/controls/numeric_input.cljs | 10 +- .../ds/controls/shared/options_dropdown.scss | 1 + .../ui/ds/controls/utilities/token_field.scss | 2 +- .../src/app/main/ui/workspace/sidebar.cljs | 1 - .../sidebar/options/menus/border_radius.cljs | 13 +- .../sidebar/options/menus/measures.cljs | 257 +++++++++++++----- 10 files changed, 209 insertions(+), 223 deletions(-) diff --git a/common/src/app/common/features.cljc b/common/src/app/common/features.cljc index 29f99d24db..d08b73a97f 100644 --- a/common/src/app/common/features.cljc +++ b/common/src/app/common/features.cljc @@ -51,6 +51,7 @@ "styles/v2" "layout/grid" "plugins/runtime" + "tokens/numeric-input" "design-tokens/v1" "text-editor/v2" "render-wasm/v1" @@ -80,6 +81,7 @@ #{"styles/v2" "plugins/runtime" "text-editor/v2" + "tokens/numeric-input" "render-wasm/v1"}) ;; Features that are mainly backend only or there are a proper @@ -97,6 +99,7 @@ "design-tokens/v1" "fdata/shape-data-type" "fdata/path-data" + "tokens/numeric-input" "variants/v1"} (into frontend-only-features) (into backend-only-features))) @@ -121,6 +124,7 @@ :feature-text-editor-v2 "text-editor/v2" :feature-render-wasm "render-wasm/v1" :feature-variants "variants/v1" + :feature-token-input "tokens/numeric-input" nil)) (defn migrate-legacy-features diff --git a/common/src/app/common/types/token.cljc b/common/src/app/common/types/token.cljc index 4ee9b523e9..74f36981a4 100644 --- a/common/src/app/common/types/token.cljc +++ b/common/src/app/common/types/token.cljc @@ -477,7 +477,7 @@ :max-height #{:sizing :dimensions} :x #{:spacing :dimensions} :y #{:spacing :dimensions} - :rotation #{:number} + :rotation #{:number :rotation} :border-radius #{:border-radius :dimensions} :row-gap #{:spacing :dimensions} :column-gap #{:spacing :dimensions} diff --git a/frontend/src/app/main/data/workspace/tokens/application.cljs b/frontend/src/app/main/data/workspace/tokens/application.cljs index 9a53b971a5..9e36845f34 100644 --- a/frontend/src/app/main/data/workspace/tokens/application.cljs +++ b/frontend/src/app/main/data/workspace/tokens/application.cljs @@ -40,137 +40,6 @@ (declare token-properties) (declare update-layout-item-margin) -;; Events to apply / unapply tokens to shapes ------------------------------------------------------------ - -(defn apply-token - "Apply `attributes` that match `token` for `shape-ids`. - - Optionally remove attributes from `attributes-to-remove`, - this is useful for applying a single attribute from an attributes set - while removing other applied tokens from this set." - [{:keys [attributes attributes-to-remove token shape-ids on-update-shape]}] - (ptk/reify ::apply-token - ptk/WatchEvent - (watch [_ state _] - ;; We do not allow to apply tokens while text editor is open. - (when (empty? (get state :workspace-editor-state)) - (let [attributes-to-remove - ;; Remove atomic typography tokens when applying composite and vice-verca - (cond - (ctt/typography-token-keys (:type token)) (set/union attributes-to-remove ctt/typography-keys) - (ctt/typography-keys (:type token)) (set/union attributes-to-remove ctt/typography-token-keys) - :else attributes-to-remove)] - (when-let [tokens (some-> (dsh/lookup-file-data state) - (get :tokens-lib) - (ctob/get-tokens-in-active-sets))] - (->> (sd/resolve-tokens tokens) - (rx/mapcat - (fn [resolved-tokens] - (let [undo-id (js/Symbol) - objects (dsh/lookup-page-objects state) - selected-shapes (select-keys objects shape-ids) - - shape-ids (or (->> selected-shapes - (filter (fn [[_ shape]] - (or - (and (ctsl/any-layout-immediate-child? objects shape) - (some ctt/spacing-margin-keys attributes)) - (ctt/any-appliable-attr? attributes (:type shape))))) - (keys)) - []) - - resolved-value (get-in resolved-tokens [(cft/token-identifier token) :resolved-value]) - tokenized-attributes (cft/attributes-map attributes token) - type (:type token)] - (rx/concat - (rx/of - (st/emit! (ev/event {::ev/name "apply-tokens" - :type type - :applyed-to attributes})) - (dwu/start-undo-transaction undo-id) - (dwsh/update-shapes shape-ids (fn [shape] - (cond-> shape - attributes-to-remove - (update :applied-tokens #(apply (partial dissoc %) attributes-to-remove)) - :always - (update :applied-tokens merge tokenized-attributes))))) - (when on-update-shape - (let [res (on-update-shape resolved-value shape-ids attributes)] - ;; Composed updates return observables and need to be executed differently - (if (rx/observable? res) - res - (rx/of res)))) - (rx/of (dwu/commit-undo-transaction undo-id))))))))))))) - -(defn apply-spacing-token - "Handles edge-case for spacing token when applying token via toggle button. - Splits out `shape-ids` into seperate default actions: - - Layouts take the `default` update function - - Shapes inside layout will only take margin" - [{:keys [token shapes]}] - (ptk/reify ::apply-spacing-token - ptk/WatchEvent - (watch [_ state _] - (let [objects (dsh/lookup-page-objects state) - - {:keys [attributes on-update-shape]} - (get token-properties (:type token)) - - {:keys [other frame-children]} - (group-by #(if (ctsl/any-layout-immediate-child? objects %) :frame-children :other) shapes)] - - (rx/of - (apply-token {:attributes attributes - :token token - :shape-ids (map :id other) - :on-update-shape on-update-shape}) - (apply-token {:attributes ctt/spacing-margin-keys - :token token - :shape-ids (map :id frame-children) - :on-update-shape update-layout-item-margin})))))) - -(defn unapply-token - "Removes `attributes` that match `token` for `shape-ids`. - - Doesn't update shape attributes." - [{:keys [attributes token shape-ids] :as _props}] - (ptk/reify ::unapply-token - ptk/WatchEvent - (watch [_ _ _] - (rx/of - (let [remove-token #(when % (cft/remove-attributes-for-token attributes token %))] - (dwsh/update-shapes - shape-ids - (fn [shape] - (update shape :applied-tokens remove-token)))))))) - -(defn toggle-token - [{:keys [token shapes attrs]}] - (ptk/reify ::on-toggle-token - ptk/WatchEvent - (watch [_ _ _] - (let [{:keys [attributes all-attributes on-update-shape]} - (get token-properties (:type token)) - - unapply-tokens? - (cft/shapes-token-applied? token shapes (or all-attributes attributes)) - - shape-ids (map :id shapes)] - (if unapply-tokens? - (rx/of - (unapply-token {:attributes (or attrs all-attributes attributes) - :token token - :shape-ids shape-ids})) - (rx/of - (case (:type token) - :spacing - (apply-spacing-token {:token token - :shapes shapes}) - (apply-token {:attributes (or attrs attributes) - :token token - :shape-ids shape-ids - :on-update-shape on-update-shape})))))))) - ;; Events to update the value of attributes with applied tokens --------------------------------------------------------- ;; (note that dwsh/update-shapes function returns an event) @@ -652,7 +521,7 @@ Splits out `shape-ids` into seperate default actions: - Layouts take the `default` update function - Shapes inside layout will only take margin" - [{:keys [token shapes]}] + [{:keys [token shapes attr]}] (ptk/reify ::apply-spacing-token ptk/WatchEvent (watch [_ state _] @@ -665,7 +534,7 @@ (group-by #(if (ctsl/any-layout-immediate-child? objects %) :frame-children :other) shapes)] (rx/of - (apply-token {:attributes attributes + (apply-token {:attributes (or attr attributes) :token token :shape-ids (map :id other) :on-update-shape on-update-shape}) @@ -690,13 +559,12 @@ (update shape :applied-tokens remove-token)))))))) (defn toggle-token - [{:keys [token shapes]}] + [{:keys [token shapes attrs]}] (ptk/reify ::on-toggle-token ptk/WatchEvent (watch [_ _ _] (let [{:keys [attributes all-attributes on-update-shape]} (get token-properties (:type token)) - unapply-tokens? (cft/shapes-token-applied? token shapes (or all-attributes attributes)) @@ -710,8 +578,9 @@ (case (:type token) :spacing (apply-spacing-token {:token token + :attr attrs :shapes shapes}) - (apply-token {:attributes attributes + (apply-token {:attributes (or attrs attributes) :token token :shape-ids shape-ids :on-update-shape on-update-shape})))))))) diff --git a/frontend/src/app/main/ui/context.cljs b/frontend/src/app/main/ui/context.cljs index 57672d4f14..59c2631ba6 100644 --- a/frontend/src/app/main/ui/context.cljs +++ b/frontend/src/app/main/ui/context.cljs @@ -24,6 +24,7 @@ (def libraries (mf/create-context nil)) (def design-tokens (mf/create-context nil)) +(def token-inputs (mf/create-context nil)) (def current-scroll (mf/create-context nil)) (def current-zoom (mf/create-context nil)) diff --git a/frontend/src/app/main/ui/ds/controls/numeric_input.cljs b/frontend/src/app/main/ui/ds/controls/numeric_input.cljs index 4c26835576..1267c8caf6 100644 --- a/frontend/src/app/main/ui/ds/controls/numeric_input.cljs +++ b/frontend/src/app/main/ui/ds/controls/numeric_input.cljs @@ -158,16 +158,17 @@ [:class {:optional true} :string] [:value {:optional true} [:maybe [:or :int + :float :string [:= :multiple]]]] [:default {:optional true} [:maybe :string]] [:placeholder {:optional true} :string] [:icon {:optional true} [:maybe schema:icon]] [:disabled {:optional true} [:maybe :boolean]] - [:min {:optional true} [:maybe :int]] - [:max {:optional true} [:maybe :int]] + [:min {:optional true} [:maybe [:or :int :float]]] + [:max {:optional true} [:maybe [:or :int :float]]] [:max-length {:optional true} :int] - [:step {:optional true} [:maybe :int]] + [:step {:optional true} [:maybe [:or :int :float]]] [:is-selected-on-focus {:optional true} :boolean] [:nillable {:optional true} :boolean] [:applied-token {:optional true} [:maybe [:or :string [:= :multiple]]]] @@ -177,7 +178,7 @@ [:on-focus {:optional true} fn?] [:on-detach {:optional true} fn?] [:property {:optional true} :string] - [:align {:optional true} [:enum :left :right]]]) + [:align {:optional true} [:maybe [:enum :left :right]]]]) (mf/defc numeric-input* {::mf/schema schema:numeric-input} @@ -195,7 +196,6 @@ tokens (if (object? tokens) (mfu/bean tokens) tokens) - value (if (= :multiple applied-token) :multiple value) diff --git a/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.scss b/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.scss index 7b98d05ccc..c5592673b9 100644 --- a/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.scss +++ b/frontend/src/app/main/ui/ds/controls/shared/options_dropdown.scss @@ -17,6 +17,7 @@ position: absolute; top: $sz-36; width: var(--dropdown-width, 100%); + transform: translateX(var(--dropdown-translate-distance, 0)); background-color: var(--options-dropdown-bg-color); border-radius: $br-8; border: $b-1 solid var(--options-dropdown-border-color); diff --git a/frontend/src/app/main/ui/ds/controls/utilities/token_field.scss b/frontend/src/app/main/ui/ds/controls/utilities/token_field.scss index 8bafa9a1fc..ab5b35484d 100644 --- a/frontend/src/app/main/ui/ds/controls/utilities/token_field.scss +++ b/frontend/src/app/main/ui/ds/controls/utilities/token_field.scss @@ -25,7 +25,7 @@ inline-size: 100%; background: var(--token-field-bg-color); border-radius: $br-8; - padding: var(--sp-s); + padding: var(--sp-xs) var(--sp-s); outline: $b-1 solid var(--token-field-outline-color); &:hover { diff --git a/frontend/src/app/main/ui/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs index a6b8e08078..3289e18bb9 100644 --- a/frontend/src/app/main/ui/workspace/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar.cljs @@ -303,7 +303,6 @@ [:> (mf/provider muc/sidebar) {:value :right} [:> (mf/provider muc/active-tokens-by-type) {:value active-tokens-by-type} - [:aside {:class (stl/css-case :right-settings-bar true :not-expand (not can-be-expanded?) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.cljs index b30ee20cbf..d2311f26d4 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/border_radius.cljs @@ -5,7 +5,7 @@ [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.components.numeric-input :as deprecated-input] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i] [app.main.ui.hooks :as hooks] @@ -68,6 +68,7 @@ (change-radius (fn [shape] (ctsr/set-radius-to-all-corners shape value)))))) + on-radius-4-change (mf/use-fn (mf/deps ids change-radius) @@ -98,7 +99,7 @@ [:> icon* {:icon-id i/corner-radius :size "s" :class (stl/css :icon)}] - [:> numeric-input* + [:> deprecated-input/numeric-input* {:placeholder (cond (not all-equal?) "Mixed" @@ -113,7 +114,7 @@ [:div {:class (stl/css :radius-4)} [:div {:class (stl/css :small-input)} - [:> numeric-input* + [:> deprecated-input/numeric-input* {:placeholder "--" :title (tr "workspace.options.radius-top-left") :min 0 @@ -121,7 +122,7 @@ :value (:r1 values)}]] [:div {:class (stl/css :small-input)} - [:> numeric-input* + [:> deprecated-input/numeric-input* {:placeholder "--" :title (tr "workspace.options.radius-top-right") :min 0 @@ -129,7 +130,7 @@ :value (:r2 values)}]] [:div {:class (stl/css :small-input)} - [:> numeric-input* + [:> deprecated-input/numeric-input* {:placeholder "--" :title (tr "workspace.options.radius-bottom-left") :min 0 @@ -137,7 +138,7 @@ :value (:r4 values)}]] [:div {:class (stl/css :small-input)} - [:> numeric-input* + [:> deprecated-input/numeric-input* {:placeholder "--" :title (tr "workspace.options.radius-bottom-right") :min 0 diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index 2e1f9af9b1..94f2982ea5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -22,14 +22,15 @@ [app.main.data.workspace.tokens.application :as dwta] [app.main.data.workspace.transforms :as dwt] [app.main.data.workspace.undo :as dwu] + [app.main.features :as features] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] - [app.main.ui.components.numeric-input :refer [numeric-input*]] + [app.main.ui.components.numeric-input :as deprecated-input] [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.context :as muc] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] - [app.main.ui.ds.controls.numeric-input :as ni] + [app.main.ui.ds.controls.numeric-input :refer [numeric-input*]] [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i] [app.main.ui.icons :as deprecated-icon] [app.main.ui.workspace.sidebar.options.menus.border-radius :refer [border-radius-menu*]] @@ -93,13 +94,17 @@ (mf/defc numeric-input-wrapper* {::mf/private true} - [{:keys [values name applied-tokens] :rest props}] + [{:keys [values name applied-tokens align on-detach] :rest props}] (let [tokens (mf/use-ctx muc/active-tokens-by-type) tokens (mf/with-memo [tokens name] (delay (-> (deref tokens) (select-keys (get tk/tokens-by-input name)) (not-empty)))) + on-detach-attr + (mf/use-fn + (mf/deps on-detach name) + #(on-detach % name)) props (mf/spread-props props {:placeholder (if (or (= :multiple (:applied-tokens values)) @@ -108,15 +113,20 @@ :class (stl/css :numeric-input-measures) :applied-token (get applied-tokens name) :tokens tokens + :align align + :on-detach on-detach-attr :value (get values name)})] - [:> ni/numeric-input* props])) + [:> numeric-input* props])) (def ^:private xf:map-type (map :type)) (def ^:private xf:mapcat-type-to-options (mapcat type->options)) (mf/defc measures-menu* [{:keys [ids values applied-tokens type shapes]}] - (let [all-types + (let [token-numeric-inputs + (features/use-feature "tokens/numeric-input") + + all-types (mf/with-memo [type shapes] ;; We only need this when multiple type is used (when (= type :multiple) @@ -281,8 +291,7 @@ (st/emit! (udw/change-orientation ids (keyword orientation))))) ;; SIZE AND PROPORTION LOCK - - on-size-change + do-size-change (mf/use-fn (mf/deps ids) (fn [value attr] @@ -290,6 +299,24 @@ (st/emit! (udw/trigger-bounding-box-cloaking ids) (udw/update-dimensions ids attr value))))) + on-size-change + (mf/use-fn + (mf/deps ids) + (fn [value attr] + (if (or (string? value) (int? value)) + (do + (st/emit! (udw/trigger-bounding-box-cloaking ids)) + (binding [cts/*wasm-sync* true] + (run! #(do-size-change value attr) shapes))) + (do + (let [resolved-value (:resolved-value (first value))] + (st/emit! (udw/trigger-bounding-box-cloaking ids) + (dwta/toggle-token {:token (first value) + :attrs #{attr} + :shapes shapes})) + (binding [cts/*wasm-sync* true] + (run! #(do-size-change resolved-value attr) shapes))))))) + on-proportion-lock-change (mf/use-fn (mf/deps ids proportion-lock) @@ -308,26 +335,43 @@ (mf/deps ids) (fn [value attr] (if (or (string? value) (int? value)) - (do (st/emit! (udw/trigger-bounding-box-cloaking ids)) - (binding [cts/*wasm-sync* true] - (run! #(do-position-change %1 value attr) shapes))) (do - (let [value2 (:resolved-value value)] + (st/emit! (udw/trigger-bounding-box-cloaking ids)) + (binding [cts/*wasm-sync* true] + (run! #(do-position-change %1 value attr) shapes))) + (do + (let [resolved-value (:resolved-value (first value))] (st/emit! (udw/trigger-bounding-box-cloaking ids) - (dwta/toggle-token {:token value + (dwta/toggle-token {:token (first value) :attrs #{attr} :shapes shapes})) (binding [cts/*wasm-sync* true] - (run! #(do-position-change %1 value2 attr) shapes))))))) + (run! #(do-position-change %1 resolved-value attr) shapes))))))) ;; ROTATION + do-rotation-change + (mf/use-fn + (mf/deps ids) + (fn [value] + (st/emit! (udw/increase-rotation ids value)))) + on-rotation-change (mf/use-fn (mf/deps ids) (fn [value] - (binding [cts/*wasm-sync* true] - (st/emit! (udw/trigger-bounding-box-cloaking ids) - (udw/increase-rotation ids value))))) + (if (or (string? value) (int? value)) + (do + (st/emit! (udw/trigger-bounding-box-cloaking ids)) + (binding [cts/*wasm-sync* true] + (run! #(do-rotation-change value) shapes))) + (do + (let [resolved-value (:resolved-value (first value))] + (st/emit! (udw/trigger-bounding-box-cloaking ids) + (dwta/toggle-token {:token (first value) + :attrs #{:rotation} + :shapes shapes})) + (binding [cts/*wasm-sync* true] + (run! #(do-rotation-change resolved-value) shapes))))))) on-width-change (mf/use-fn (mf/deps on-size-change) #(on-size-change % :width)) @@ -341,15 +385,16 @@ on-pos-y-change (mf/use-fn (mf/deps on-position-change) #(on-position-change % :y)) + + ;; DETACH on-detach-token (mf/use-fn (mf/deps ids) (fn [token attr] - ;; Review this, detach is having problems - (let [shape-ids (map :id shapes)] - (st/emit! (dwta/unapply-token {:token token - :attributes #{attr} - :shape-ids shape-ids}))))) + (st/emit! (dwta/unapply-token {:token (first token) + :attributes #{attr} + :shape-ids ids})))) + ;; CLIP CONTENT AND SHOW IN VIEWER on-change-clip-content (mf/use-fn @@ -432,28 +477,55 @@ (when (options :size) [:div {:class (stl/css :size)} - [:div {:class (stl/css-case :width true - :disabled disabled-width-sizing?) - :title (tr "workspace.options.width")} - [:span {:class (stl/css :icon-text)} "W"] - [:> numeric-input* {:min 0.01 - :no-validate true - :placeholder (if (= :multiple (:width values)) (tr "settings.multiple") "--") - :on-change on-width-change - :disabled disabled-width-sizing? - :class (stl/css :numeric-input) - :value (:width values)}]] - [:div {:class (stl/css-case :height true - :disabled disabled-height-sizing?) - :title (tr "workspace.options.height")} - [:span {:class (stl/css :icon-text)} "H"] - [:> numeric-input* {:min 0.01 - :no-validate true - :placeholder (if (= :multiple (:height values)) (tr "settings.multiple") "--") - :on-change on-height-change - :disabled disabled-height-sizing? - :class (stl/css :numeric-input) - :value (:height values)}]] + (if token-numeric-inputs + [:* + [:> numeric-input-wrapper* + {:disabled disabled-width-sizing? + :on-change on-width-change + :on-detach on-detach-token + :icon i/character-w + :min 0.01 + :name :width + :property (tr "workspace.options.width") + :applied-tokens applied-tokens + :values values}] + + [:> numeric-input-wrapper* + {:disabled disabled-height-sizing? + :on-change on-height-change + :on-detach on-detach-token + :min 0.01 + :icon i/character-h + :name :height + :align :right + :property (tr "workspace.options.height") + :applied-tokens applied-tokens + :values values}]] + + [:* + [:div {:class (stl/css-case :width true + :disabled disabled-width-sizing?) + :title (tr "workspace.options.width")} + [:span {:class (stl/css :icon-text)} "W"] + [:> deprecated-input/numeric-input* + {:min 0.01 + :no-validate true + :placeholder (if (= :multiple (:width values)) (tr "settings.multiple") "--") + :on-change on-width-change + :disabled disabled-width-sizing? + :class (stl/css :numeric-input) + :value (:width values)}]] + [:div {:class (stl/css-case :height true + :disabled disabled-height-sizing?) + :title (tr "workspace.options.height")} + [:span {:class (stl/css :icon-text)} "H"] + [:> deprecated-input/numeric-input* {:min 0.01 + :no-validate true + :placeholder (if (= :multiple (:height values)) (tr "settings.multiple") "--") + :on-change on-height-change + :disabled disabled-height-sizing? + :class (stl/css :numeric-input) + :value (:height values)}]]]) [:> icon-button* {:variant "ghost" :icon (if proportion-lock "lock" "unlock") @@ -464,45 +536,84 @@ (when (options :position) [:div {:class (stl/css :position)} - [:> numeric-input-wrapper* - {:disabled disabled-position? - :on-change on-position-change - :on-detach on-detach-token - :icon "character-x" - :name :x - :property (tr "workspace.options.x") - :applied-tokens applied-tokens - :values values}] + (if token-numeric-inputs + [:* + [:> numeric-input-wrapper* + {:disabled disabled-position? + :on-change on-pos-x-change + :on-detach on-detach-token + :icon i/character-x + :name :x + :property (tr "workspace.options.x") + :applied-tokens applied-tokens + :values values}] + [:> numeric-input-wrapper* + {:disabled disabled-position? + :on-change on-pos-y-change + :on-detach on-detach-token + :icon i/character-y + :name :y + :align :right + :property (tr "workspace.options.y") + :applied-tokens applied-tokens + :values values}]] - [:> numeric-input-wrapper* - {:disabled disabled-position? - :on-change on-position-change - :on-detach on-detach-token - :icon "character-y" - :name :y - :property (tr "workspace.options.y") - :applied-tokens applied-tokens - :values values}]]) + [:* + [:div {:class (stl/css-case :x-position true + :disabled disabled-position?) + :title (tr "workspace.options.x")} + [:span {:class (stl/css :icon-text)} "X"] + [:> deprecated-input/numeric-input* {:no-validate true + :placeholder (if (= :multiple (:x values)) (tr "settings.multiple") "--") + :on-change on-pos-x-change + :disabled disabled-position? + :class (stl/css :numeric-input) + :value (:x values)}]] + + [:div {:class (stl/css-case :y-position true + :disabled disabled-position?) + :title (tr "workspace.options.y")} + [:span {:class (stl/css :icon-text)} "Y"] + [:> deprecated-input/numeric-input* {:no-validate true + :placeholder (if (= :multiple (:y values)) (tr "settings.multiple") "--") + :disabled disabled-position? + :on-change on-pos-y-change + :class (stl/css :numeric-input) + :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")} - [:span {:class (stl/css :icon)} deprecated-icon/rotation] - [:> numeric-input* - {:no-validate true - :min -359 - :max 359 - :data-wrap true - :placeholder (if (= :multiple (:rotation values)) (tr "settings.multiple") "--") - :on-change on-rotation-change - :class (stl/css :numeric-input) - :value (:rotation values)}]]) + (if token-numeric-inputs + [:> numeric-input-wrapper* + {:on-change on-rotation-change + :on-detach on-detach-token + :icon i/rotation + :min -359 + :max 359 + :name :rotation + :property (tr "workspace.options.rotation") + :applied-tokens applied-tokens + :values values}] + + [:div {:class (stl/css :rotation) + :title (tr "workspace.options.rotation")} + [:span {:class (stl/css :icon)} deprecated-icon/rotation] + [:> deprecated-input/numeric-input* + {:no-validate true + :min -359 + :max 359 + :data-wrap true + :placeholder (if (= :multiple (:rotation values)) (tr "settings.multiple") "--") + :on-change on-rotation-change + :class (stl/css :numeric-input) + :value (:rotation values)}]])) (when (options :radius) [:> border-radius-menu* {:class (stl/css :border-radius) :ids ids :values values + :applied-tokens applied-tokens + :shapes shapes :shape shape}])]) (when (or (options :clip-content) (options :show-in-viewer)) [:div {:class (stl/css :clip-show)}