mirror of
https://github.com/penpot/penpot.git
synced 2026-09-14 07:59:36 +00:00
🐛 Fix broken attribute on numeric input (#8250)
* 🐛 Fix broken attribute on numeric input * 🐛 Fix tooltip position
This commit is contained in:
parent
8acd031ab2
commit
a5e36dbb3d
@ -16,6 +16,7 @@
|
|||||||
(def ^:private schema:icon-button
|
(def ^:private schema:icon-button
|
||||||
[:map
|
[:map
|
||||||
[:class {:optional true} :string]
|
[:class {:optional true} :string]
|
||||||
|
[:tooltip-class {:optional true} [:maybe :string]]
|
||||||
[:icon-class {:optional true} :string]
|
[:icon-class {:optional true} :string]
|
||||||
[:icon
|
[:icon
|
||||||
[:and :string [:fn #(contains? icon-list %)]]]
|
[:and :string [:fn #(contains? icon-list %)]]]
|
||||||
@ -28,7 +29,7 @@
|
|||||||
(mf/defc icon-button*
|
(mf/defc icon-button*
|
||||||
{::mf/schema schema:icon-button
|
{::mf/schema schema:icon-button
|
||||||
::mf/memo true}
|
::mf/memo true}
|
||||||
[{:keys [class icon icon-class variant aria-label children tooltip-placement] :rest props}]
|
[{:keys [class icon icon-class variant aria-label children tooltip-placement tooltip-class] :rest props}]
|
||||||
(let [variant
|
(let [variant
|
||||||
(d/nilv variant "primary")
|
(d/nilv variant "primary")
|
||||||
|
|
||||||
@ -49,6 +50,7 @@
|
|||||||
:aria-labelledby tooltip-id})]
|
:aria-labelledby tooltip-id})]
|
||||||
|
|
||||||
[:> tooltip* {:content aria-label
|
[:> tooltip* {:content aria-label
|
||||||
|
:class tooltip-class
|
||||||
:placement tooltip-placement
|
:placement tooltip-placement
|
||||||
:id tooltip-id}
|
:id tooltip-id}
|
||||||
[:> :button props
|
[:> :button props
|
||||||
|
|||||||
@ -18,7 +18,6 @@
|
|||||||
[app.main.ui.ds.controls.utilities.input-field :refer [input-field*]]
|
[app.main.ui.ds.controls.utilities.input-field :refer [input-field*]]
|
||||||
[app.main.ui.ds.controls.utilities.token-field :refer [token-field*]]
|
[app.main.ui.ds.controls.utilities.token-field :refer [token-field*]]
|
||||||
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list] :as i]
|
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list] :as i]
|
||||||
[app.main.ui.ds.tooltip :refer [tooltip*]]
|
|
||||||
[app.main.ui.formats :as fmt]
|
[app.main.ui.formats :as fmt]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :refer [tr]]
|
[app.util.i18n :refer [tr]]
|
||||||
@ -638,27 +637,17 @@
|
|||||||
:on-change store-raw-value
|
:on-change store-raw-value
|
||||||
:variant "comfortable"
|
:variant "comfortable"
|
||||||
:disabled disabled
|
:disabled disabled
|
||||||
:slot-start (when (or icon text-icon)
|
:icon icon
|
||||||
|
:aria-label property
|
||||||
|
:slot-start (when text-icon
|
||||||
(mf/html
|
(mf/html
|
||||||
[:> tooltip*
|
[:div {:class (stl/css :text-icon)}
|
||||||
{:content property
|
text-icon]))
|
||||||
: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
|
:slot-end (when-not disabled
|
||||||
(when (some? tokens)
|
(when (some? tokens)
|
||||||
(mf/html [:> icon-button* {:variant "ghost"
|
(mf/html [:> icon-button* {:variant "ghost"
|
||||||
:icon i/tokens
|
:icon i/tokens
|
||||||
|
:tooltip-class (stl/css :button-tooltip)
|
||||||
:class (stl/css :invisible-button)
|
:class (stl/css :invisible-button)
|
||||||
:aria-label (tr "ds.inputs.numeric-input.open-token-list-dropdown")
|
:aria-label (tr "ds.inputs.numeric-input.open-token-list-dropdown")
|
||||||
:ref open-dropdown-ref
|
:ref open-dropdown-ref
|
||||||
@ -686,23 +675,19 @@
|
|||||||
:disabled disabled
|
:disabled disabled
|
||||||
:on-blur on-blur
|
:on-blur on-blur
|
||||||
:class inner-class
|
:class inner-class
|
||||||
|
:property property
|
||||||
:slot-start (when (or icon text-icon)
|
:slot-start (when (or icon text-icon)
|
||||||
(mf/html
|
(mf/html
|
||||||
[:> tooltip*
|
(cond
|
||||||
{:content property
|
icon
|
||||||
:id property}
|
[:> icon*
|
||||||
(cond
|
{:icon-id icon
|
||||||
icon
|
:size "s"
|
||||||
[:> icon*
|
:class (stl/css :icon)}]
|
||||||
{:icon-id icon
|
|
||||||
:size "s"
|
|
||||||
:aria-labelledby property
|
|
||||||
:class (stl/css :icon)}]
|
|
||||||
|
|
||||||
text-icon
|
text-icon
|
||||||
[:div {:class (stl/css :text-icon)
|
[:div {:class (stl/css :text-icon)}
|
||||||
:aria-labelledby property}
|
text-icon])))
|
||||||
text-icon])]))
|
|
||||||
:token-wrapper-ref token-wrapper-ref
|
:token-wrapper-ref token-wrapper-ref
|
||||||
:token-detach-btn-ref token-detach-btn-ref
|
:token-detach-btn-ref token-detach-btn-ref
|
||||||
:detach-token detach-token})))]
|
:detach-token detach-token})))]
|
||||||
@ -737,40 +722,21 @@
|
|||||||
(mf/with-effect [dropdown-options]
|
(mf/with-effect [dropdown-options]
|
||||||
(mf/set-ref-val! options-ref dropdown-options))
|
(mf/set-ref-val! options-ref dropdown-options))
|
||||||
|
|
||||||
(if (some? icon)
|
[:div {:class [class (stl/css :input-wrapper)]
|
||||||
[:div {:class [class (stl/css :input-wrapper)]
|
:ref wrapper-ref}
|
||||||
:ref wrapper-ref}
|
|
||||||
|
|
||||||
(if (and (some? token-applied)
|
(if (and (some? token-applied)
|
||||||
(not= :multiple token-applied))
|
(not= :multiple token-applied))
|
||||||
[:> token-field* token-props]
|
[:> token-field* token-props]
|
||||||
[:> input-field* input-props])
|
[:> input-field* input-props])
|
||||||
|
|
||||||
(when ^boolean is-open
|
(when ^boolean is-open
|
||||||
(let [options (if (delay? dropdown-options) @dropdown-options dropdown-options)]
|
(let [options (if (delay? dropdown-options) @dropdown-options dropdown-options)]
|
||||||
[:> options-dropdown* {:on-click on-option-click
|
[:> options-dropdown* {:on-click on-option-click
|
||||||
:id listbox-id
|
:id listbox-id
|
||||||
:options options
|
:options options
|
||||||
:selected selected-id
|
:selected selected-id
|
||||||
:focused focused-id
|
:focused focused-id
|
||||||
:align align
|
:align align
|
||||||
:empty-to-end empty-to-end
|
:empty-to-end empty-to-end
|
||||||
:ref set-option-ref}]))]
|
:ref set-option-ref}]))]))
|
||||||
[:div {:class [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])
|
|
||||||
|
|
||||||
(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}]))])))
|
|
||||||
|
|||||||
@ -55,3 +55,8 @@
|
|||||||
--opacity-button: 1;
|
--opacity-button: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-tooltip {
|
||||||
|
inline-size: var($sz-28);
|
||||||
|
block-size: 100%;
|
||||||
|
}
|
||||||
|
|||||||
@ -42,7 +42,6 @@
|
|||||||
type (d/nilv type "text")
|
type (d/nilv type "text")
|
||||||
variant (d/nilv variant "dense")
|
variant (d/nilv variant "dense")
|
||||||
tooltip-id (mf/use-id)
|
tooltip-id (mf/use-id)
|
||||||
|
|
||||||
props (mf/spread-props props
|
props (mf/spread-props props
|
||||||
{:class [class
|
{:class [class
|
||||||
(stl/css-case
|
(stl/css-case
|
||||||
@ -54,15 +53,11 @@
|
|||||||
"true")
|
"true")
|
||||||
:aria-describedby (when has-hint
|
:aria-describedby (when has-hint
|
||||||
(str id "-hint"))
|
(str id "-hint"))
|
||||||
|
:aria-labelledby tooltip-id
|
||||||
:type (d/nilv type "text")
|
:type (d/nilv type "text")
|
||||||
:id id
|
:id id
|
||||||
:max-length (d/nilv max-length max-input-length)})
|
:max-length (d/nilv max-length max-input-length)})
|
||||||
|
|
||||||
props (if (and aria-label (not (some? icon)))
|
|
||||||
(mf/spread-props props
|
|
||||||
{:aria-label aria-label})
|
|
||||||
(mf/spread-props props
|
|
||||||
{:aria-labelledby tooltip-id}))
|
|
||||||
inside-class (stl/css-case :input-wrapper true
|
inside-class (stl/css-case :input-wrapper true
|
||||||
:has-hint has-hint
|
:has-hint has-hint
|
||||||
:hint-type-hint (= hint-type "hint")
|
:hint-type-hint (= hint-type "hint")
|
||||||
@ -83,11 +78,14 @@
|
|||||||
(when (some? slot-start)
|
(when (some? slot-start)
|
||||||
slot-start)
|
slot-start)
|
||||||
(when (some? icon)
|
(when (some? icon)
|
||||||
(if aria-label
|
[:> icon* {:icon-id icon
|
||||||
[:> tooltip* {:content aria-label
|
:class (stl/css :icon)
|
||||||
:id tooltip-id}
|
:size "s"
|
||||||
[:> icon* {:icon-id icon :class (stl/css :icon) :on-click on-icon-click}]]
|
:on-click on-icon-click}])
|
||||||
[:> icon* {:icon-id icon :class (stl/css :icon) :on-click on-icon-click}]))
|
(if aria-label
|
||||||
[:> "input" props]
|
[:> tooltip* {:content aria-label
|
||||||
|
:id tooltip-id}
|
||||||
|
[:> "input" props]]
|
||||||
|
[:> "input" props])
|
||||||
(when (some? slot-end)
|
(when (some? slot-end)
|
||||||
slot-end)]))
|
slot-end)]))
|
||||||
|
|||||||
@ -118,4 +118,5 @@
|
|||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
color: var(--color-foreground-secondary);
|
color: var(--color-foreground-secondary);
|
||||||
|
min-inline-size: var(--sp-l);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,7 @@
|
|||||||
[:class {:optional true} [:maybe :string]]
|
[:class {:optional true} [:maybe :string]]
|
||||||
[:id {:optional true} [:maybe :string]]
|
[:id {:optional true} [:maybe :string]]
|
||||||
[:label {:optional true} [:maybe :string]]
|
[:label {:optional true} [:maybe :string]]
|
||||||
|
[:property {:optional true} [:maybe :string]]
|
||||||
[:value :any]
|
[:value :any]
|
||||||
[:disabled {:optional true} :boolean]
|
[:disabled {:optional true} :boolean]
|
||||||
[:slot-start {:optional true} [:maybe some?]]
|
[:slot-start {:optional true} [:maybe some?]]
|
||||||
@ -35,7 +36,7 @@
|
|||||||
{::mf/schema schema:token-field}
|
{::mf/schema schema:token-field}
|
||||||
[{:keys [id label value slot-start disabled class
|
[{:keys [id label value slot-start disabled class
|
||||||
on-click on-token-key-down on-blur detach-token
|
on-click on-token-key-down on-blur detach-token
|
||||||
token-wrapper-ref token-detach-btn-ref on-focus]}]
|
token-wrapper-ref token-detach-btn-ref on-focus property]}]
|
||||||
(let [set-active? (some? id)
|
(let [set-active? (some? id)
|
||||||
content (if set-active?
|
content (if set-active?
|
||||||
label
|
label
|
||||||
@ -50,37 +51,42 @@
|
|||||||
(when-not ^boolean disabled
|
(when-not ^boolean disabled
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(dom/focus! (mf/ref-val token-wrapper-ref)))))]
|
(dom/focus! (mf/ref-val token-wrapper-ref)))))]
|
||||||
|
[:> tooltip* {:content property
|
||||||
|
:class (stl/css :token-field-wrapper)
|
||||||
|
:id (dm/str default-id "-input")}
|
||||||
|
[:div {:class [class (stl/css-case :token-field true
|
||||||
|
:with-icon (some? slot-start)
|
||||||
|
:token-field-disabled disabled)]
|
||||||
|
:on-click focus-wrapper
|
||||||
|
:disabled disabled
|
||||||
|
:on-key-down on-token-key-down
|
||||||
|
:ref token-wrapper-ref
|
||||||
|
:on-blur on-blur
|
||||||
|
:on-focus on-focus
|
||||||
|
:aria-labelledby (dm/str default-id "-input")
|
||||||
|
:tab-index (if disabled -1 0)}
|
||||||
|
|
||||||
[:div {:class [class (stl/css-case :token-field true
|
(when (some? slot-start) slot-start)
|
||||||
:with-icon (some? slot-start)
|
|
||||||
:token-field-disabled disabled)]
|
|
||||||
:on-click focus-wrapper
|
|
||||||
:disabled disabled
|
|
||||||
:on-key-down on-token-key-down
|
|
||||||
:ref token-wrapper-ref
|
|
||||||
:on-blur on-blur
|
|
||||||
:on-focus on-focus
|
|
||||||
:tab-index (if disabled -1 0)}
|
|
||||||
|
|
||||||
(when (some? slot-start) slot-start)
|
[:div {:class (stl/css :content-wrapper)}
|
||||||
|
[:> tooltip* {:content content
|
||||||
|
:id (dm/str id "-pill")}
|
||||||
|
[:button {:on-click on-click
|
||||||
|
:class (stl/css-case :pill true
|
||||||
|
:no-set-pill (not set-active?)
|
||||||
|
:pill-disabled disabled)
|
||||||
|
:disabled disabled
|
||||||
|
:aria-labelledby (dm/str id "-pill")
|
||||||
|
:on-key-down on-token-key-down}
|
||||||
|
value
|
||||||
|
(when-not set-active?
|
||||||
|
[:div {:class (stl/css :pill-dot)}])]]]
|
||||||
|
|
||||||
[:> tooltip* {:content content
|
(when-not ^boolean disabled
|
||||||
:id (dm/str id "-pill")}
|
[:> icon-button* {:variant "ghost"
|
||||||
[:button {:on-click on-click
|
:class (stl/css :invisible-button)
|
||||||
:class (stl/css-case :pill true
|
:tooltip-class (stl/css :button-tooltip)
|
||||||
:no-set-pill (not set-active?)
|
:icon i/broken-link
|
||||||
:pill-disabled disabled)
|
:ref token-detach-btn-ref
|
||||||
:disabled disabled
|
:aria-label (tr "ds.inputs.token-field.detach-token")
|
||||||
:aria-labelledby (dm/str id "-pill")
|
:on-click detach-token}])]]))
|
||||||
:on-key-down on-token-key-down}
|
|
||||||
value
|
|
||||||
(when-not set-active?
|
|
||||||
[:div {:class (stl/css :pill-dot)}])]]
|
|
||||||
|
|
||||||
(when-not ^boolean disabled
|
|
||||||
[:> icon-button* {:variant "ghost"
|
|
||||||
:class (stl/css :invisible-button)
|
|
||||||
:icon i/broken-link
|
|
||||||
:ref token-detach-btn-ref
|
|
||||||
:aria-label (tr "ds.inputs.token-field.detach-token")
|
|
||||||
:on-click detach-token}])]))
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
@use "ds/typography.scss" as t;
|
@use "ds/typography.scss" as t;
|
||||||
@use "ds/colors.scss" as *;
|
@use "ds/colors.scss" as *;
|
||||||
@use "ds/mixins.scss" as *;
|
@use "ds/mixins.scss" as *;
|
||||||
|
@use "ds/_utils.scss" as *;
|
||||||
|
|
||||||
.token-field {
|
.token-field {
|
||||||
--token-field-bg-color: var(--color-background-tertiary);
|
--token-field-bg-color: var(--color-background-tertiary);
|
||||||
@ -37,6 +38,9 @@
|
|||||||
--token-field-outline-color: var(--color-accent-primary);
|
--token-field-outline-color: var(--color-accent-primary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.token-field-wrapper {
|
||||||
|
inline-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.with-icon {
|
.with-icon {
|
||||||
grid-template-columns: auto 1fr;
|
grid-template-columns: auto 1fr;
|
||||||
@ -132,3 +136,12 @@
|
|||||||
--opacity-button: 1;
|
--opacity-button: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-wrapper {
|
||||||
|
inline-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-tooltip {
|
||||||
|
inline-size: px2rem(28);
|
||||||
|
block-size: 100%;
|
||||||
|
}
|
||||||
|
|||||||
@ -171,7 +171,7 @@
|
|||||||
|
|
||||||
(def ^:private schema:tooltip
|
(def ^:private schema:tooltip
|
||||||
[:map
|
[:map
|
||||||
[:class {:optional true} :string]
|
[:class {:optional true} [:maybe :string]]
|
||||||
[:id {:optional true} :string]
|
[:id {:optional true} :string]
|
||||||
[:offset {:optional true} :int]
|
[:offset {:optional true} :int]
|
||||||
[:delay {:optional true} :int]
|
[:delay {:optional true} :int]
|
||||||
@ -184,6 +184,7 @@
|
|||||||
[{:keys [class id children content placement offset delay] :rest props}]
|
[{:keys [class id children content placement offset delay] :rest props}]
|
||||||
(let [internal-id
|
(let [internal-id
|
||||||
(mf/use-id)
|
(mf/use-id)
|
||||||
|
trigger-ref (mf/use-ref nil)
|
||||||
|
|
||||||
id
|
id
|
||||||
(d/nilv id internal-id)
|
(d/nilv id internal-id)
|
||||||
@ -204,19 +205,23 @@
|
|||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps id placement offset)
|
(mf/deps id placement offset)
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(clear-schedule schedule-ref)
|
|
||||||
(when-let [tooltip (dom/get-element id)]
|
|
||||||
(let [origin-brect
|
|
||||||
(->> (dom/get-target event)
|
|
||||||
(dom/get-bounding-rect))
|
|
||||||
|
|
||||||
update-position
|
(let [current (dom/get-current-target event)
|
||||||
(fn []
|
related (dom/get-related-target event)
|
||||||
(let [new-placement (update-tooltip-position tooltip placement origin-brect offset)]
|
is-node? (fn [node] (and node (.-nodeType node)))]
|
||||||
(when (not= new-placement placement)
|
(when-not (and related (is-node? related) (.contains current related))
|
||||||
(reset! placement* new-placement))))]
|
(clear-schedule schedule-ref)
|
||||||
|
(when-let [tooltip (dom/get-element id)]
|
||||||
|
(let [origin-brect
|
||||||
|
(dom/get-bounding-rect (mf/ref-val trigger-ref))
|
||||||
|
|
||||||
(add-schedule schedule-ref delay update-position)))))
|
update-position
|
||||||
|
(fn []
|
||||||
|
(let [new-placement (update-tooltip-position tooltip placement origin-brect offset)]
|
||||||
|
(when (not= new-placement placement)
|
||||||
|
(reset! placement* new-placement))))]
|
||||||
|
|
||||||
|
(add-schedule schedule-ref delay update-position)))))))
|
||||||
|
|
||||||
on-hide
|
on-hide
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@ -252,6 +257,7 @@
|
|||||||
:on-focus on-show
|
:on-focus on-show
|
||||||
:on-blur on-hide
|
:on-blur on-hide
|
||||||
:on-key-down handle-key-down
|
:on-key-down handle-key-down
|
||||||
|
:ref trigger-ref
|
||||||
:class [class (stl/css :tooltip-trigger)]
|
:class [class (stl/css :tooltip-trigger)]
|
||||||
:aria-describedby id})
|
:aria-describedby id})
|
||||||
content
|
content
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user