mirror of
https://github.com/penpot/penpot.git
synced 2025-05-23 14:26:12 +02:00
♻️ Refactor (again) numeric input component
This commit is contained in:
parent
e96d129ee8
commit
ab0245279f
11 changed files with 182 additions and 198 deletions
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
(ns app.main.ui.components.color-input
|
(ns app.main.ui.components.color-input
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
[app.util.color :as uc]
|
[app.util.color :as uc]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.globals :as globals]
|
[app.util.globals :as globals]
|
||||||
|
@ -13,8 +14,7 @@
|
||||||
[app.util.keyboard :as kbd]
|
[app.util.keyboard :as kbd]
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
[goog.events :as events]
|
[goog.events :as events]
|
||||||
[rumext.v2 :as mf])
|
[rumext.v2 :as mf]))
|
||||||
(:import goog.events.EventType))
|
|
||||||
|
|
||||||
(defn clean-color
|
(defn clean-color
|
||||||
[value]
|
[value]
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
on-change (obj/get props "onChange")
|
on-change (obj/get props "onChange")
|
||||||
on-blur (obj/get props "onBlur")
|
on-blur (obj/get props "onBlur")
|
||||||
on-focus (obj/get props "onFocus")
|
on-focus (obj/get props "onFocus")
|
||||||
select-on-focus? (obj/get props "data-select-on-focus" 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
|
||||||
;; of this component may provide one (that is forwarded here).
|
;; of this component may provide one (that is forwarded here).
|
||||||
|
@ -128,8 +128,10 @@
|
||||||
;; In webkit browsers the mouseup event will be called after the on-focus causing and unselect
|
;; In webkit browsers the mouseup event will be called after the on-focus causing and unselect
|
||||||
(.addEventListener target "mouseup" on-mouse-up #js {"once" true})))))
|
(.addEventListener target "mouseup" on-mouse-up #js {"once" true})))))
|
||||||
|
|
||||||
props (-> props
|
props (-> (obj/clone props)
|
||||||
(obj/without ["value" "onChange" "onFocus"])
|
(obj/unset! "selectOnFocus")
|
||||||
|
(obj/set! "value" mf/undefined)
|
||||||
|
(obj/set! "onChange" mf/undefined)
|
||||||
(obj/set! "type" "text")
|
(obj/set! "type" "text")
|
||||||
(obj/set! "ref" ref)
|
(obj/set! "ref" ref)
|
||||||
;; (obj/set! "list" list-id)
|
;; (obj/set! "list" list-id)
|
||||||
|
@ -157,8 +159,8 @@
|
||||||
|
|
||||||
(mf/use-layout-effect
|
(mf/use-layout-effect
|
||||||
(fn []
|
(fn []
|
||||||
(let [keys [(events/listen globals/window EventType.POINTERDOWN on-click)
|
(let [keys [(events/listen globals/window "pointerdown" on-click)
|
||||||
(events/listen globals/window EventType.CLICK on-click)]]
|
(events/listen globals/window "click" on-click)]]
|
||||||
#(doseq [key keys]
|
#(doseq [key keys]
|
||||||
(events/unlistenByKey key)))))
|
(events/unlistenByKey key)))))
|
||||||
|
|
||||||
|
|
|
@ -7,35 +7,43 @@
|
||||||
(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.spec :as us]
|
[app.common.schema :as sm]
|
||||||
[app.main.ui.formats :as fmt]
|
[app.main.ui.formats :as fmt]
|
||||||
|
[app.main.ui.hooks :as h]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.globals :as globals]
|
[app.util.globals :as globals]
|
||||||
[app.util.keyboard :as kbd]
|
[app.util.keyboard :as kbd]
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
[app.util.simple-math :as sm]
|
[app.util.simple-math :as smt]
|
||||||
|
[cljs.core :as c]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[goog.events :as events]
|
[goog.events :as events]
|
||||||
[rumext.v2 :as mf])
|
[rumext.v2 :as mf]))
|
||||||
(:import goog.events.EventType))
|
|
||||||
|
|
||||||
(mf/defc numeric-input
|
(mf/defc numeric-input
|
||||||
{::mf/wrap-props false
|
{::mf/wrap-props false
|
||||||
::mf/forward-ref true}
|
::mf/forward-ref true}
|
||||||
[props external-ref]
|
[props external-ref]
|
||||||
(let [value-str (obj/get props "value")
|
(let [value-str (unchecked-get props "value")
|
||||||
min-val-str (obj/get props "min")
|
min-value (unchecked-get props "min")
|
||||||
max-val-str (obj/get props "max")
|
max-value (unchecked-get props "max")
|
||||||
step-val-str (obj/get props "step")
|
step-value (unchecked-get props "step")
|
||||||
wrap-value? (obj/get props "data-wrap")
|
wrap-value? (unchecked-get props "data-wrap")
|
||||||
on-change (obj/get props "onChange")
|
on-change (unchecked-get props "onChange")
|
||||||
on-blur (obj/get props "onBlur")
|
on-blur (unchecked-get props "onBlur")
|
||||||
on-focus (obj/get props "onFocus")
|
on-focus (unchecked-get props "onFocus")
|
||||||
title (obj/get props "title")
|
|
||||||
default-val (obj/get props "default")
|
title (unchecked-get props "title")
|
||||||
nillable (obj/get props "nillable")
|
default (unchecked-get props "default")
|
||||||
select-on-focus? (obj/get props "data-select-on-focus" true)
|
nillable? (unchecked-get props "nillable")
|
||||||
class (obj/get props "klass")
|
class (d/nilv (unchecked-get props "className") "input-text")
|
||||||
|
|
||||||
|
min-value (d/parse-double min-value)
|
||||||
|
max-value (d/parse-double max-value)
|
||||||
|
step-value (d/parse-double step-value 1)
|
||||||
|
default (d/parse-double default 0)
|
||||||
|
|
||||||
|
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
|
||||||
;; of this component may provide one (that is forwarded here).
|
;; of this component may provide one (that is forwarded here).
|
||||||
|
@ -43,117 +51,91 @@
|
||||||
local-ref (mf/use-ref)
|
local-ref (mf/use-ref)
|
||||||
ref (or external-ref local-ref)
|
ref (or external-ref local-ref)
|
||||||
|
|
||||||
;; We need to store the handle-blur ref so we can call it on unmount
|
|
||||||
handle-blur-ref (mf/use-ref nil)
|
|
||||||
dirty-ref (mf/use-ref false)
|
|
||||||
|
|
||||||
;; This `value` represents the previous value and is used as
|
;; This `value` represents the previous value and is used as
|
||||||
;; initil value for the simple math expression evaluation.
|
;; initil value for the simple math expression evaluation.
|
||||||
value (d/parse-double value-str default-val)
|
value (d/parse-double value-str default)
|
||||||
|
|
||||||
min-val (cond
|
;; We need to store the handle-blur ref so we can call it on unmount
|
||||||
(number? min-val-str)
|
dirty-ref (mf/use-ref false)
|
||||||
min-val-str
|
|
||||||
|
|
||||||
(string? min-val-str)
|
|
||||||
(d/parse-double min-val-str))
|
|
||||||
|
|
||||||
max-val (cond
|
|
||||||
(number? max-val-str)
|
|
||||||
max-val-str
|
|
||||||
|
|
||||||
(string? max-val-str)
|
|
||||||
(d/parse-double max-val-str))
|
|
||||||
|
|
||||||
step-val (cond
|
|
||||||
(number? step-val-str)
|
|
||||||
step-val-str
|
|
||||||
|
|
||||||
(string? step-val-str)
|
|
||||||
(d/parse-double step-val-str)
|
|
||||||
|
|
||||||
:else 1)
|
|
||||||
|
|
||||||
parse-value
|
parse-value
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps ref min-val max-val value nillable default-val)
|
(mf/deps min-value max-value value nillable? default)
|
||||||
(fn []
|
(fn []
|
||||||
(let [input-node (mf/ref-val ref)
|
(when-let [node (mf/ref-val ref)]
|
||||||
new-value (-> (dom/get-value input-node)
|
(let [new-value (-> (dom/get-value node)
|
||||||
(str/strip-suffix ".")
|
(str/strip-suffix ".")
|
||||||
(sm/expr-eval value))]
|
(smt/expr-eval value))]
|
||||||
(cond
|
(cond
|
||||||
(d/num? new-value)
|
(d/num? new-value)
|
||||||
(-> new-value
|
(-> new-value
|
||||||
(cljs.core/max (/ us/min-safe-int 2))
|
(d/max (/ sm/min-safe-int 2))
|
||||||
(cljs.core/min (/ us/max-safe-int 2))
|
(d/min (/ sm/max-safe-int 2))
|
||||||
(cond->
|
(cond-> (d/num? min-value)
|
||||||
(d/num? min-val)
|
(d/max min-value))
|
||||||
(cljs.core/max min-val)
|
(cond-> (d/num? max-value)
|
||||||
|
(d/min max-value)))
|
||||||
|
|
||||||
(d/num? max-val)
|
nillable?
|
||||||
(cljs.core/min max-val)))
|
default
|
||||||
|
|
||||||
nillable
|
:else value)))))
|
||||||
default-val
|
|
||||||
|
|
||||||
:else value))))
|
|
||||||
|
|
||||||
update-input
|
update-input
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps ref)
|
|
||||||
(fn [new-value]
|
(fn [new-value]
|
||||||
(let [input-node (mf/ref-val ref)]
|
(when-let [node (mf/ref-val ref)]
|
||||||
(dom/set-value! input-node (fmt/format-number new-value)))))
|
(dom/set-value! node (fmt/format-number new-value)))))
|
||||||
|
|
||||||
apply-value
|
apply-value
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps on-change update-input value)
|
(mf/deps on-change update-input value)
|
||||||
(fn [new-value event]
|
(fn [event new-value]
|
||||||
(mf/set-ref-val! dirty-ref false)
|
(mf/set-ref-val! dirty-ref false)
|
||||||
(when (and (not= new-value value)
|
(when (and (not= new-value value)
|
||||||
(fn? on-change))
|
(fn? on-change))
|
||||||
|
;; FIXME: on-change very slow, makes the handler laggy
|
||||||
(on-change new-value event))
|
(on-change new-value event))
|
||||||
(update-input new-value)))
|
(update-input new-value)))
|
||||||
|
|
||||||
set-delta
|
set-delta
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps wrap-value? min-val max-val parse-value apply-value)
|
(mf/deps wrap-value? min-value max-value parse-value apply-value)
|
||||||
(fn [event up? down?]
|
(fn [event up? down?]
|
||||||
(let [current-value (parse-value)]
|
(let [current-value (parse-value)]
|
||||||
(when current-value
|
(when current-value
|
||||||
(let [increment (cond
|
(let [increment (cond
|
||||||
(kbd/shift? event)
|
(kbd/shift? event)
|
||||||
(if up? (* step-val 10) (* step-val -10))
|
(if up? (* step-value 10) (* step-value -10))
|
||||||
|
|
||||||
(kbd/alt? event)
|
(kbd/alt? event)
|
||||||
(if up? (* step-val 0.1) (* step-val -0.1))
|
(if up? (* step-value 0.1) (* step-value -0.1))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(if up? step-val (- step-val)))
|
(if up? step-value (- step-value)))
|
||||||
|
|
||||||
new-value (+ current-value increment)
|
new-value (+ current-value increment)
|
||||||
new-value (cond
|
new-value (cond
|
||||||
(and wrap-value? (d/num? max-val min-val)
|
(and wrap-value? (d/num? max-value min-value)
|
||||||
(> new-value max-val) up?)
|
(> new-value max-value) up?)
|
||||||
(-> new-value (- max-val) (+ min-val) (- step-val))
|
(-> new-value (- max-value) (+ min-value) (- step-value))
|
||||||
|
|
||||||
(and wrap-value? (d/num? max-val min-val)
|
(and wrap-value? (d/num? max-value min-value)
|
||||||
(< new-value min-val) down?)
|
(< new-value min-value) down?)
|
||||||
(-> new-value (- min-val) (+ max-val) (+ step-val))
|
(-> new-value (- min-value) (+ max-value) (+ step-value))
|
||||||
|
|
||||||
(and (d/num? min-val) (< new-value min-val))
|
(and (d/num? min-value) (< new-value min-value))
|
||||||
min-val
|
min-value
|
||||||
|
|
||||||
(and (d/num? max-val) (> new-value max-val))
|
(and (d/num? max-value) (> new-value max-value))
|
||||||
max-val
|
max-value
|
||||||
|
|
||||||
:else new-value)]
|
:else new-value)]
|
||||||
|
|
||||||
(apply-value new-value event))))))
|
(apply-value event new-value))))))
|
||||||
|
|
||||||
handle-key-down
|
handle-key-down
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps set-delta apply-value update-input)
|
(mf/deps set-delta apply-value update-input)
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(mf/set-ref-val! dirty-ref true)
|
(mf/set-ref-val! dirty-ref true)
|
||||||
|
@ -161,44 +143,47 @@
|
||||||
down? (kbd/down-arrow? event)
|
down? (kbd/down-arrow? event)
|
||||||
enter? (kbd/enter? event)
|
enter? (kbd/enter? event)
|
||||||
esc? (kbd/esc? event)
|
esc? (kbd/esc? event)
|
||||||
input-node (mf/ref-val ref)]
|
node (mf/ref-val ref)]
|
||||||
(when (or up? down?)
|
(when (or up? down?)
|
||||||
(set-delta event up? down?))
|
(set-delta event up? down?))
|
||||||
(when enter?
|
(when enter?
|
||||||
(dom/blur! input-node))
|
(dom/blur! node))
|
||||||
(when esc?
|
(when esc?
|
||||||
(update-input value-str)
|
(update-input value-str)
|
||||||
(dom/blur! input-node)))))
|
(dom/blur! node)))))
|
||||||
|
|
||||||
handle-mouse-wheel
|
handle-mouse-wheel
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps set-delta)
|
(mf/deps set-delta)
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [input-node (mf/ref-val ref)]
|
(when-let [node (mf/ref-val ref)]
|
||||||
(when (dom/active? input-node)
|
(when (dom/active? node)
|
||||||
(let [event (.getBrowserEvent ^js event)]
|
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(set-delta event (< (.-deltaY event) 0) (> (.-deltaY event) 0)))))))
|
(let [{:keys [y]} (dom/get-delta-position event)]
|
||||||
|
(set-delta event (< y 0) (> y 0)))))))
|
||||||
|
|
||||||
handle-blur
|
handle-blur
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps parse-value apply-value update-input on-blur)
|
(mf/deps parse-value apply-value update-input on-blur)
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [new-value (or (parse-value) default-val)]
|
(let [new-value (or (parse-value) default)]
|
||||||
(if (or nillable new-value)
|
(if (or nillable? new-value)
|
||||||
(apply-value new-value event)
|
(apply-value event new-value)
|
||||||
(update-input new-value)))
|
(update-input new-value)))
|
||||||
(when on-blur (on-blur event))))
|
(when (fn? on-blur)
|
||||||
|
(on-blur event))))
|
||||||
|
|
||||||
|
handle-unmount
|
||||||
|
(h/use-ref-callback handle-blur)
|
||||||
|
|
||||||
on-click
|
on-click
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [target (dom/get-target event)]
|
(let [target (dom/get-target event)
|
||||||
(when (some? ref)
|
node (mf/ref-val ref)]
|
||||||
(let [current (mf/ref-val ref)]
|
(when (and (some? node) (not (dom/child? node target)))
|
||||||
(when (and (some? current) (not (.contains current target)))
|
(dom/blur! node)))))
|
||||||
(dom/blur! current)))))))
|
|
||||||
|
|
||||||
handle-focus
|
handle-focus
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
|
@ -212,9 +197,12 @@
|
||||||
;; In webkit browsers the mouseup event will be called after the on-focus causing and unselect
|
;; In webkit browsers the mouseup event will be called after the on-focus causing and unselect
|
||||||
(.addEventListener target "mouseup" dom/prevent-default #js {:once true})))))
|
(.addEventListener target "mouseup" dom/prevent-default #js {:once true})))))
|
||||||
|
|
||||||
props (-> props
|
props (-> (obj/clone props)
|
||||||
(obj/without ["value" "onChange" "nillable" "onFocus"])
|
(obj/unset! "selectOnFocus")
|
||||||
(obj/set! "className" (or class "input-text"))
|
(obj/unset! "nillable")
|
||||||
|
(obj/set! "value" mf/undefined)
|
||||||
|
(obj/set! "onChange" mf/undefined)
|
||||||
|
(obj/set! "className" class)
|
||||||
(obj/set! "type" "text")
|
(obj/set! "type" "text")
|
||||||
(obj/set! "ref" ref)
|
(obj/set! "ref" ref)
|
||||||
(obj/set! "defaultValue" (fmt/format-number value))
|
(obj/set! "defaultValue" (fmt/format-number value))
|
||||||
|
@ -223,50 +211,23 @@
|
||||||
(obj/set! "onBlur" handle-blur)
|
(obj/set! "onBlur" handle-blur)
|
||||||
(obj/set! "onFocus" handle-focus))]
|
(obj/set! "onFocus" handle-focus))]
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/with-effect [value]
|
||||||
(mf/deps value)
|
|
||||||
(fn []
|
|
||||||
(when-let [input-node (mf/ref-val ref)]
|
(when-let [input-node (mf/ref-val ref)]
|
||||||
(dom/set-value! input-node (fmt/format-number value)))))
|
(dom/set-value! input-node (fmt/format-number value))))
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/with-effect []
|
||||||
(mf/deps handle-blur)
|
|
||||||
(fn []
|
(fn []
|
||||||
(mf/set-ref-val! handle-blur-ref {:fn handle-blur})))
|
(when (mf/ref-val dirty-ref)
|
||||||
|
(handle-unmount))))
|
||||||
|
|
||||||
(mf/use-layout-effect
|
(mf/with-layout-effect []
|
||||||
(fn []
|
(let [keys [(events/listen globals/window "pointerdown" on-click)
|
||||||
#(when (mf/ref-val dirty-ref)
|
(events/listen globals/window "click" on-click)]]
|
||||||
(let [handle-blur (:fn (mf/ref-val handle-blur-ref))]
|
#(run! events/unlistenByKey keys)))
|
||||||
(handle-blur)))))
|
|
||||||
|
|
||||||
(mf/use-layout-effect
|
(mf/with-layout-effect [handle-mouse-wheel]
|
||||||
(mf/deps handle-mouse-wheel)
|
(when-let [node (mf/ref-val ref)]
|
||||||
(fn []
|
(let [key (events/listen node "wheel" handle-mouse-wheel #js {:passive false})]
|
||||||
(let [keys [(events/listen (mf/ref-val ref) EventType.WHEEL handle-mouse-wheel #js {:passive false})]]
|
#(events/unlistenByKey key))))
|
||||||
#(doseq [key keys]
|
|
||||||
(events/unlistenByKey key)))))
|
|
||||||
|
|
||||||
(mf/use-layout-effect
|
|
||||||
(fn []
|
|
||||||
(let [keys [(events/listen globals/window EventType.POINTERDOWN on-click)
|
|
||||||
(events/listen globals/window EventType.CLICK on-click)]]
|
|
||||||
#(doseq [key keys]
|
|
||||||
(events/unlistenByKey key)))))
|
|
||||||
|
|
||||||
(mf/use-layout-effect
|
|
||||||
(mf/deps handle-mouse-wheel)
|
|
||||||
(fn []
|
|
||||||
(let [keys [(events/listen (mf/ref-val ref) EventType.WHEEL handle-mouse-wheel #js {:passive false})]]
|
|
||||||
#(doseq [key keys]
|
|
||||||
(events/unlistenByKey key)))))
|
|
||||||
|
|
||||||
|
|
||||||
(mf/use-layout-effect
|
|
||||||
(mf/deps handle-mouse-wheel)
|
|
||||||
(fn []
|
|
||||||
(let [keys [(events/listen (mf/ref-val ref) EventType.WHEEL handle-mouse-wheel #js {:passive false})]]
|
|
||||||
#(doseq [key keys]
|
|
||||||
(events/unlistenByKey key)))))
|
|
||||||
|
|
||||||
[:> :input props]))
|
[:> :input props]))
|
||||||
|
|
|
@ -151,7 +151,7 @@
|
||||||
:on-remove (on-remove index)
|
:on-remove (on-remove index)
|
||||||
:disable-drag disable-drag
|
:disable-drag disable-drag
|
||||||
:on-focus on-focus
|
:on-focus on-focus
|
||||||
:data-select-on-focus (not @disable-drag)
|
:select-on-focus (not @disable-drag)
|
||||||
:on-blur on-blur}])])
|
:on-blur on-blur}])])
|
||||||
|
|
||||||
(when (or (= type :frame)
|
(when (or (= type :frame)
|
||||||
|
|
|
@ -189,6 +189,6 @@
|
||||||
:on-reorder (handle-reorder index)
|
:on-reorder (handle-reorder index)
|
||||||
:disable-drag disable-drag
|
:disable-drag disable-drag
|
||||||
:on-focus on-focus
|
:on-focus on-focus
|
||||||
:data-select-on-focus (not @disable-drag)
|
:select-on-focus (not @disable-drag)
|
||||||
:on-blur on-blur
|
:on-blur on-blur
|
||||||
:disable-stroke-style disable-stroke-style}])])]]))
|
:disable-stroke-style disable-stroke-style}])])]]))
|
||||||
|
|
|
@ -461,7 +461,7 @@
|
||||||
:max 200
|
:max 200
|
||||||
:step 0.1
|
:step 0.1
|
||||||
:default "1.2"
|
:default "1.2"
|
||||||
:klass (css :line-height-input)
|
:class (css :line-height-input)
|
||||||
:value (attr->string line-height)
|
:value (attr->string line-height)
|
||||||
:placeholder (tr "settings.multiple")
|
:placeholder (tr "settings.multiple")
|
||||||
:nillable line-height-nillable
|
:nillable line-height-nillable
|
||||||
|
@ -477,7 +477,7 @@
|
||||||
{:min -200
|
{:min -200
|
||||||
:max 200
|
:max 200
|
||||||
:step 0.1
|
:step 0.1
|
||||||
:klass (css :letter-spacing-input)
|
:class (css :letter-spacing-input)
|
||||||
:value (attr->string letter-spacing)
|
:value (attr->string letter-spacing)
|
||||||
:placeholder (tr "settings.multiple")
|
:placeholder (tr "settings.multiple")
|
||||||
:on-change #(handle-change % :letter-spacing)
|
:on-change #(handle-change % :letter-spacing)
|
||||||
|
|
|
@ -17,26 +17,18 @@
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(mf/defc options
|
(mf/defc options
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]
|
||||||
|
::mf/wrap-props false}
|
||||||
[]
|
[]
|
||||||
(let [options (mf/deref refs/workspace-page-options)
|
(let [options (mf/deref refs/workspace-page-options)
|
||||||
|
on-change (mf/use-fn #(st/emit! (dw/change-canvas-color %)))
|
||||||
on-change
|
on-open (mf/use-fn #(st/emit! (dwu/start-undo-transaction :options)))
|
||||||
(fn [value]
|
on-close (mf/use-fn #(st/emit! (dwu/commit-undo-transaction :options)))]
|
||||||
(st/emit! (dw/change-canvas-color value)))
|
|
||||||
|
|
||||||
on-open
|
|
||||||
(fn []
|
|
||||||
(st/emit! (dwu/start-undo-transaction :options)))
|
|
||||||
|
|
||||||
on-close
|
|
||||||
(fn []
|
|
||||||
(st/emit! (dwu/commit-undo-transaction :options)))]
|
|
||||||
|
|
||||||
[:div.element-set
|
[:div.element-set
|
||||||
[:div.element-set-title (tr "workspace.options.canvas-background")]
|
[:div.element-set-title (tr "workspace.options.canvas-background")]
|
||||||
[:div.element-set-content
|
[:div.element-set-content
|
||||||
[:& color-row {:disable-gradient true
|
[:& color-row
|
||||||
|
{:disable-gradient true
|
||||||
:disable-opacity true
|
:disable-opacity true
|
||||||
:title (tr "workspace.options.canvas-background")
|
:title (tr "workspace.options.canvas-background")
|
||||||
:color {:color (get options :background clr/canvas)
|
:color {:color (get options :background clr/canvas)
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
(mf/defc color-row
|
(mf/defc color-row
|
||||||
[{:keys [index color disable-gradient disable-opacity on-change
|
[{:keys [index color disable-gradient disable-opacity on-change
|
||||||
on-reorder on-detach on-open on-close title on-remove
|
on-reorder on-detach on-open on-close title on-remove
|
||||||
disable-drag on-focus on-blur select-only data-select-on-focus]}]
|
disable-drag on-focus on-blur select-only select-on-focus]}]
|
||||||
(let [current-file-id (mf/use-ctx ctx/current-file-id)
|
(let [current-file-id (mf/use-ctx ctx/current-file-id)
|
||||||
file-colors (mf/deref refs/workspace-file-colors)
|
file-colors (mf/deref refs/workspace-file-colors)
|
||||||
shared-libs (mf/deref refs/workspace-libraries)
|
shared-libs (mf/deref refs/workspace-libraries)
|
||||||
|
@ -207,7 +207,7 @@
|
||||||
{:class (dom/classnames :percentail (not= (:opacity color) :multiple))}
|
{:class (dom/classnames :percentail (not= (:opacity color) :multiple))}
|
||||||
[:> numeric-input {:value (-> color :opacity opacity->string)
|
[:> numeric-input {:value (-> color :opacity opacity->string)
|
||||||
:placeholder (tr "settings.multiple")
|
:placeholder (tr "settings.multiple")
|
||||||
:data-select-on-focus data-select-on-focus
|
:select-on-focus select-on-focus
|
||||||
:on-focus on-focus
|
:on-focus on-focus
|
||||||
:on-blur on-blur
|
:on-blur on-blur
|
||||||
:on-change handle-opacity-change
|
:on-change handle-opacity-change
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(mf/defc input-row [{:keys [label options value class min max on-change type placeholder default nillable on-focus data-select-on-focus]}]
|
(mf/defc input-row
|
||||||
|
[{:keys [label options value class min max on-change type placeholder default nillable on-focus select-on-focus]}]
|
||||||
[:div.row-flex.input-row
|
[:div.row-flex.input-row
|
||||||
[:span.element-set-subtitle label]
|
[:span.element-set-subtitle label]
|
||||||
[:div.input-element {:class class}
|
[:div.input-element {:class class}
|
||||||
|
@ -47,7 +48,7 @@
|
||||||
:nillable nillable
|
:nillable nillable
|
||||||
:on-change on-change
|
:on-change on-change
|
||||||
:on-focus on-focus
|
:on-focus on-focus
|
||||||
:data-select-on-focus data-select-on-focus
|
:select-on-focus select-on-focus
|
||||||
:value (or value "")}])]])
|
:value (or value "")}])]])
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
(mf/defc stroke-row
|
(mf/defc stroke-row
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[{:keys [index stroke title show-caps on-color-change on-reorder on-color-detach on-remove on-stroke-width-change on-stroke-style-change on-stroke-alignment-change open-caps-select close-caps-select on-stroke-cap-start-change on-stroke-cap-end-change on-stroke-cap-switch disable-drag on-focus on-blur disable-stroke-style data-select-on-focus]}]
|
[{:keys [index stroke title show-caps on-color-change on-reorder on-color-detach on-remove on-stroke-width-change on-stroke-style-change on-stroke-alignment-change open-caps-select close-caps-select on-stroke-cap-start-change on-stroke-cap-end-change on-stroke-cap-switch disable-drag on-focus on-blur disable-stroke-style select-on-focus]}]
|
||||||
(let [start-caps-state (mf/use-state {:open? false
|
(let [start-caps-state (mf/use-state {:open? false
|
||||||
:top 0
|
:top 0
|
||||||
:left 0})
|
:left 0})
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
:on-remove (on-remove index)
|
:on-remove (on-remove index)
|
||||||
:disable-drag disable-drag
|
:disable-drag disable-drag
|
||||||
:on-focus on-focus
|
:on-focus on-focus
|
||||||
:data-select-on-focus data-select-on-focus
|
:select-on-focus select-on-focus
|
||||||
:on-blur on-blur}]
|
:on-blur on-blur}]
|
||||||
|
|
||||||
;; Stroke Width, Alignment & Style
|
;; Stroke Width, Alignment & Style
|
||||||
|
@ -103,7 +103,7 @@
|
||||||
:placeholder (tr "settings.multiple")
|
:placeholder (tr "settings.multiple")
|
||||||
:on-change (on-stroke-width-change index)
|
:on-change (on-stroke-width-change index)
|
||||||
:on-focus on-focus
|
:on-focus on-focus
|
||||||
:data-select-on-focus data-select-on-focus
|
:select-on-focus select-on-focus
|
||||||
:on-blur on-blur}]]
|
:on-blur on-blur}]]
|
||||||
|
|
||||||
[:select#style.input-select {:value (enum->string (:stroke-alignment stroke))
|
[:select#style.input-select {:value (enum->string (:stroke-alignment stroke))
|
||||||
|
|
|
@ -17,7 +17,21 @@
|
||||||
[app.util.webapi :as wapi]
|
[app.util.webapi :as wapi]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[goog.dom :as dom]
|
[goog.dom :as dom]
|
||||||
[promesa.core :as p]))
|
[promesa.core :as p])
|
||||||
|
(:import goog.events.BrowserEvent))
|
||||||
|
|
||||||
|
(extend-type BrowserEvent
|
||||||
|
cljs.core/IDeref
|
||||||
|
(-deref [it] (.getBrowserEvent it)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn browser-event?
|
||||||
|
[o]
|
||||||
|
(instance? BrowserEvent o))
|
||||||
|
|
||||||
|
(defn native-event?
|
||||||
|
[o]
|
||||||
|
(instance? js/Event o))
|
||||||
|
|
||||||
(log/set-level! :warn)
|
(log/set-level! :warn)
|
||||||
|
|
||||||
|
@ -338,10 +352,19 @@
|
||||||
y (.-offsetY event)]
|
y (.-offsetY event)]
|
||||||
(gpt/point x y))))
|
(gpt/point x y))))
|
||||||
|
|
||||||
|
(defn get-delta-position
|
||||||
|
[event]
|
||||||
|
(let [e (if (browser-event? event)
|
||||||
|
(deref event)
|
||||||
|
event)
|
||||||
|
x (.-deltaX ^js e)
|
||||||
|
y (.-deltaY ^js e)]
|
||||||
|
(gpt/point x y)))
|
||||||
|
|
||||||
(defn get-client-size
|
(defn get-client-size
|
||||||
[^js node]
|
[^js node]
|
||||||
(when (some? node)
|
(when (some? node)
|
||||||
(grc/make-rect 0 0 (.-clientWidth ^js node) (.-clientHeight ^js node))))
|
(grc/make-rect 0 0 (.-clientWidth node) (.-clientHeight node))))
|
||||||
|
|
||||||
(defn get-bounding-rect
|
(defn get-bounding-rect
|
||||||
[node]
|
[node]
|
||||||
|
|
|
@ -73,6 +73,11 @@
|
||||||
(unchecked-set obj key value)
|
(unchecked-set obj key value)
|
||||||
obj)
|
obj)
|
||||||
|
|
||||||
|
(defn unset!
|
||||||
|
[obj key]
|
||||||
|
(js-delete obj key)
|
||||||
|
obj)
|
||||||
|
|
||||||
(defn update!
|
(defn update!
|
||||||
[obj key f & args]
|
[obj key f & args]
|
||||||
(let [found (get obj key ::not-found)]
|
(let [found (get obj key ::not-found)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue