mirror of
https://github.com/penpot/penpot.git
synced 2026-08-01 19:06:18 +00:00
🐛 Fix non-integer row/column values in grid cell position inputs (#8869)
* 🐛 Fix non-integer row/column values in grid cell position inputs The numeric-input component allows Alt+arrow key increments of 0.1x the step value, which could produce float values (e.g. 4.5, 0.5) when users adjusted grid cell row/column/row-span/column-span positions. The schema requires these fields to be integers, causing backend validation errors. Round the input values to integers in the on-grid-coordinates callback before passing them to update-grid-cell-position. Signed-off-by: Andrey Antukh <niwi@niwi.nz> * 🐛 Enforce integer-only values in grid cell numeric inputs Add an `integer` prop to the legacy `numeric-input*` component that rounds parsed values in `parse-value`, ensuring all input paths (typed text, arrow keys, Alt+arrow, mouse wheel, expressions) produce integers. Use it for all six row/column inputs in the grid cell options panel. Signed-off-by: Andrey Antukh <niwi@niwi.nz> --------- Signed-off-by: Andrey Antukh <niwi@niwi.nz>
This commit is contained in:
parent
c8675c5b7e
commit
cb33fe417e
@ -7,6 +7,7 @@
|
|||||||
(ns app.main.ui.components.numeric-input
|
(ns app.main.ui.components.numeric-input
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
|
[app.common.math :as mth]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.main.ui.formats :as fmt]
|
[app.main.ui.formats :as fmt]
|
||||||
[app.main.ui.hooks :as h]
|
[app.main.ui.hooks :as h]
|
||||||
@ -43,6 +44,7 @@
|
|||||||
step-value (d/parse-double step-value 1)
|
step-value (d/parse-double step-value 1)
|
||||||
default (d/parse-double default (when-not nillable? 0))
|
default (d/parse-double default (when-not nillable? 0))
|
||||||
|
|
||||||
|
integer? (unchecked-get props "integer")
|
||||||
select-on-focus? (d/nilv (unchecked-get props "selectOnFocus") true)
|
select-on-focus? (d/nilv (unchecked-get props "selectOnFocus") true)
|
||||||
|
|
||||||
;; We need a ref pointing to the input dom element, but the user
|
;; We need a ref pointing to the input dom element, but the user
|
||||||
@ -63,7 +65,7 @@
|
|||||||
|
|
||||||
parse-value
|
parse-value
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps min-value max-value value nillable? default)
|
(mf/deps min-value max-value value nillable? default integer?)
|
||||||
(fn []
|
(fn []
|
||||||
(when-let [node (mf/ref-val ref)]
|
(when-let [node (mf/ref-val ref)]
|
||||||
(let [new-value (-> (dom/get-value node)
|
(let [new-value (-> (dom/get-value node)
|
||||||
@ -72,6 +74,7 @@
|
|||||||
(cond
|
(cond
|
||||||
(d/num? new-value)
|
(d/num? new-value)
|
||||||
(-> new-value
|
(-> new-value
|
||||||
|
(cond-> integer? mth/round)
|
||||||
(d/max (/ sm/min-safe-int 2))
|
(d/max (/ sm/min-safe-int 2))
|
||||||
(d/min (/ sm/max-safe-int 2))
|
(d/min (/ sm/max-safe-int 2))
|
||||||
(cond-> (d/num? min-value)
|
(cond-> (d/num? min-value)
|
||||||
@ -146,7 +149,8 @@
|
|||||||
(and (d/num? max-value) (> new-value max-value))
|
(and (d/num? max-value) (> new-value max-value))
|
||||||
max-value
|
max-value
|
||||||
|
|
||||||
:else new-value)]
|
:else new-value)
|
||||||
|
new-value (if integer? (mth/round new-value) new-value)]
|
||||||
|
|
||||||
(apply-value event new-value))))))
|
(apply-value event new-value))))))
|
||||||
|
|
||||||
@ -227,6 +231,7 @@
|
|||||||
props (-> (obj/clone props)
|
props (-> (obj/clone props)
|
||||||
(obj/unset! "selectOnFocus")
|
(obj/unset! "selectOnFocus")
|
||||||
(obj/unset! "nillable")
|
(obj/unset! "nillable")
|
||||||
|
(obj/unset! "integer")
|
||||||
(obj/set! "value" mf/undefined)
|
(obj/set! "value" mf/undefined)
|
||||||
(obj/set! "onChange" handle-change)
|
(obj/set! "onChange" handle-change)
|
||||||
(obj/set! "className" class)
|
(obj/set! "className" class)
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
[app.common.attrs :as attrs]
|
[app.common.attrs :as attrs]
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
|
[app.common.math :as mth]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.grid-layout.editor :as dwge]
|
[app.main.data.workspace.grid-layout.editor :as dwge]
|
||||||
@ -133,7 +134,10 @@
|
|||||||
(mf/deps column row (:id shape) (:id cell))
|
(mf/deps column row (:id shape) (:id cell))
|
||||||
(fn [field type value]
|
(fn [field type value]
|
||||||
(when-not multiple?
|
(when-not multiple?
|
||||||
(let [[property value]
|
(let [value (mth/round value)
|
||||||
|
column (mth/round column)
|
||||||
|
row (mth/round row)
|
||||||
|
[property value]
|
||||||
(cond
|
(cond
|
||||||
(and (= type :column) (or (= field :all) (= field :start)))
|
(and (= type :column) (or (= field :all) (= field :start)))
|
||||||
[:column value]
|
[:column value]
|
||||||
@ -216,6 +220,7 @@
|
|||||||
:title "Column"
|
:title "Column"
|
||||||
:on-click #(dom/select-target %)
|
:on-click #(dom/select-target %)
|
||||||
:on-change (partial on-grid-coordinates :all :column)
|
:on-change (partial on-grid-coordinates :all :column)
|
||||||
|
:integer true
|
||||||
:value column}]]]
|
:value column}]]]
|
||||||
|
|
||||||
[:div {:class (stl/css :grid-coord-group)}
|
[:div {:class (stl/css :grid-coord-group)}
|
||||||
@ -226,6 +231,7 @@
|
|||||||
:title "Row"
|
:title "Row"
|
||||||
:on-click #(dom/select-target %)
|
:on-click #(dom/select-target %)
|
||||||
:on-change (partial on-grid-coordinates :all :row)
|
:on-change (partial on-grid-coordinates :all :row)
|
||||||
|
:integer true
|
||||||
:value row}]]]])
|
:value row}]]]])
|
||||||
|
|
||||||
(when (and (not multiple?) (or (= :manual cell-mode) (= :area cell-mode)))
|
(when (and (not multiple?) (or (= :manual cell-mode) (= :area cell-mode)))
|
||||||
@ -237,12 +243,14 @@
|
|||||||
{:placeholder "--"
|
{:placeholder "--"
|
||||||
:on-pointer-down #(dom/select-target %)
|
:on-pointer-down #(dom/select-target %)
|
||||||
:on-change (partial on-grid-coordinates :start :column)
|
:on-change (partial on-grid-coordinates :start :column)
|
||||||
|
:integer true
|
||||||
:value column}]]
|
:value column}]]
|
||||||
[:div {:class (stl/css :coord-input)}
|
[:div {:class (stl/css :coord-input)}
|
||||||
[:> numeric-input*
|
[:> numeric-input*
|
||||||
{:placeholder "--"
|
{:placeholder "--"
|
||||||
:on-pointer-down #(dom/select-target %)
|
:on-pointer-down #(dom/select-target %)
|
||||||
:on-change (partial on-grid-coordinates :end :column)
|
:on-change (partial on-grid-coordinates :end :column)
|
||||||
|
:integer true
|
||||||
:value column-end}]]]
|
:value column-end}]]]
|
||||||
|
|
||||||
[:div {:class (stl/css :grid-coord-group)}
|
[:div {:class (stl/css :grid-coord-group)}
|
||||||
@ -252,12 +260,14 @@
|
|||||||
{:placeholder "--"
|
{:placeholder "--"
|
||||||
:on-pointer-down #(dom/select-target %)
|
:on-pointer-down #(dom/select-target %)
|
||||||
:on-change (partial on-grid-coordinates :start :row)
|
:on-change (partial on-grid-coordinates :start :row)
|
||||||
|
:integer true
|
||||||
:value row}]]
|
:value row}]]
|
||||||
[:div {:class (stl/css :coord-input)}
|
[:div {:class (stl/css :coord-input)}
|
||||||
[:> numeric-input*
|
[:> numeric-input*
|
||||||
{:placeholder "--"
|
{:placeholder "--"
|
||||||
:on-pointer-down #(dom/select-target %)
|
:on-pointer-down #(dom/select-target %)
|
||||||
:on-change (partial on-grid-coordinates :end :row)
|
:on-change (partial on-grid-coordinates :end :row)
|
||||||
|
:integer true
|
||||||
:value row-end}]]]])
|
:value row-end}]]]])
|
||||||
|
|
||||||
[:div {:class (stl/css :row)}
|
[:div {:class (stl/css :row)}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user