diff --git a/frontend/src/app/main/ui/ds/buttons/icon_button.cljs b/frontend/src/app/main/ui/ds/buttons/icon_button.cljs index 551142e757..3d766db460 100644 --- a/frontend/src/app/main/ui/ds/buttons/icon_button.cljs +++ b/frontend/src/app/main/ui/ds/buttons/icon_button.cljs @@ -16,6 +16,7 @@ (def ^:private schema:icon-button [:map [:class {:optional true} :string] + [:tooltip-class {:optional true} [:maybe :string]] [:icon-class {:optional true} :string] [:icon [:and :string [:fn #(contains? icon-list %)]]] @@ -28,7 +29,7 @@ (mf/defc icon-button* {::mf/schema schema:icon-button ::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 (d/nilv variant "primary") @@ -49,6 +50,7 @@ :aria-labelledby tooltip-id})] [:> tooltip* {:content aria-label + :class tooltip-class :placement tooltip-placement :id tooltip-id} [:> :button props 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 e22841ac7d..63cb9d3bf4 100644 --- a/frontend/src/app/main/ui/ds/controls/numeric_input.cljs +++ b/frontend/src/app/main/ui/ds/controls/numeric_input.cljs @@ -18,7 +18,6 @@ [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.foundations.assets.icon :refer [icon* icon-list] :as i] - [app.main.ui.ds.tooltip :refer [tooltip*]] [app.main.ui.formats :as fmt] [app.util.dom :as dom] [app.util.i18n :refer [tr]] @@ -638,27 +637,17 @@ :on-change store-raw-value :variant "comfortable" :disabled disabled - :slot-start (when (or icon text-icon) + :icon icon + :aria-label property + :slot-start (when 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])])) + [:div {:class (stl/css :text-icon)} + text-icon])) :slot-end (when-not disabled (when (some? tokens) (mf/html [:> icon-button* {:variant "ghost" :icon i/tokens + :tooltip-class (stl/css :button-tooltip) :class (stl/css :invisible-button) :aria-label (tr "ds.inputs.numeric-input.open-token-list-dropdown") :ref open-dropdown-ref @@ -686,23 +675,19 @@ :disabled disabled :on-blur on-blur :class inner-class + :property property :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)}] + (cond + icon + [:> icon* + {:icon-id icon + :size "s" + :class (stl/css :icon)}] - text-icon - [:div {:class (stl/css :text-icon) - :aria-labelledby property} - text-icon])])) + text-icon + [:div {:class (stl/css :text-icon)} + text-icon]))) :token-wrapper-ref token-wrapper-ref :token-detach-btn-ref token-detach-btn-ref :detach-token detach-token})))] @@ -737,40 +722,21 @@ (mf/with-effect [dropdown-options] (mf/set-ref-val! options-ref dropdown-options)) - (if (some? icon) - [:div {:class [class (stl/css :input-wrapper)] - :ref wrapper-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]) + (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}]))] - [: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}]))]))) + (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}]))])) diff --git a/frontend/src/app/main/ui/ds/controls/numeric_input.scss b/frontend/src/app/main/ui/ds/controls/numeric_input.scss index b3c7506529..7825f6a7fb 100644 --- a/frontend/src/app/main/ui/ds/controls/numeric_input.scss +++ b/frontend/src/app/main/ui/ds/controls/numeric_input.scss @@ -55,3 +55,8 @@ --opacity-button: 1; } } + +.button-tooltip { + inline-size: var($sz-28); + block-size: 100%; +} diff --git a/frontend/src/app/main/ui/ds/controls/utilities/input_field.cljs b/frontend/src/app/main/ui/ds/controls/utilities/input_field.cljs index ece0fdb5d2..53ffe32317 100644 --- a/frontend/src/app/main/ui/ds/controls/utilities/input_field.cljs +++ b/frontend/src/app/main/ui/ds/controls/utilities/input_field.cljs @@ -42,7 +42,6 @@ type (d/nilv type "text") variant (d/nilv variant "dense") tooltip-id (mf/use-id) - props (mf/spread-props props {:class [class (stl/css-case @@ -54,15 +53,11 @@ "true") :aria-describedby (when has-hint (str id "-hint")) + :aria-labelledby tooltip-id :type (d/nilv type "text") :id id :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 :has-hint has-hint :hint-type-hint (= hint-type "hint") @@ -83,11 +78,14 @@ (when (some? slot-start) slot-start) (when (some? icon) - (if aria-label - [:> tooltip* {:content aria-label - :id tooltip-id} - [:> icon* {:icon-id icon :class (stl/css :icon) :on-click on-icon-click}]] - [:> icon* {:icon-id icon :class (stl/css :icon) :on-click on-icon-click}])) - [:> "input" props] + [:> icon* {:icon-id icon + :class (stl/css :icon) + :size "s" + :on-click on-icon-click}]) + (if aria-label + [:> tooltip* {:content aria-label + :id tooltip-id} + [:> "input" props]] + [:> "input" props]) (when (some? slot-end) slot-end)])) diff --git a/frontend/src/app/main/ui/ds/controls/utilities/input_field.scss b/frontend/src/app/main/ui/ds/controls/utilities/input_field.scss index 3e95b194d9..a141bb3914 100644 --- a/frontend/src/app/main/ui/ds/controls/utilities/input_field.scss +++ b/frontend/src/app/main/ui/ds/controls/utilities/input_field.scss @@ -118,4 +118,5 @@ .icon { color: var(--color-foreground-secondary); + min-inline-size: var(--sp-l); } diff --git a/frontend/src/app/main/ui/ds/controls/utilities/token_field.cljs b/frontend/src/app/main/ui/ds/controls/utilities/token_field.cljs index 2e61cebdd8..8f4920ae69 100644 --- a/frontend/src/app/main/ui/ds/controls/utilities/token_field.cljs +++ b/frontend/src/app/main/ui/ds/controls/utilities/token_field.cljs @@ -22,6 +22,7 @@ [:class {:optional true} [:maybe :string]] [:id {:optional true} [:maybe :string]] [:label {:optional true} [:maybe :string]] + [:property {:optional true} [:maybe :string]] [:value :any] [:disabled {:optional true} :boolean] [:slot-start {:optional true} [:maybe some?]] @@ -35,7 +36,7 @@ {::mf/schema schema:token-field} [{:keys [id label value slot-start disabled class 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) content (if set-active? label @@ -50,37 +51,42 @@ (when-not ^boolean disabled (dom/prevent-default event) (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 - :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) - (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 - :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)}])]] - - (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}])])) + (when-not ^boolean disabled + [:> icon-button* {:variant "ghost" + :class (stl/css :invisible-button) + :tooltip-class (stl/css :button-tooltip) + :icon i/broken-link + :ref token-detach-btn-ref + :aria-label (tr "ds.inputs.token-field.detach-token") + :on-click detach-token}])]])) 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 14c32957ba..e96c5b583e 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 @@ -9,6 +9,7 @@ @use "ds/typography.scss" as t; @use "ds/colors.scss" as *; @use "ds/mixins.scss" as *; +@use "ds/_utils.scss" as *; .token-field { --token-field-bg-color: var(--color-background-tertiary); @@ -37,6 +38,9 @@ --token-field-outline-color: var(--color-accent-primary); } } +.token-field-wrapper { + inline-size: 100%; +} .with-icon { grid-template-columns: auto 1fr; @@ -132,3 +136,12 @@ --opacity-button: 1; } } + +.content-wrapper { + inline-size: 100%; +} + +.button-tooltip { + inline-size: px2rem(28); + block-size: 100%; +} diff --git a/frontend/src/app/main/ui/ds/tooltip/tooltip.cljs b/frontend/src/app/main/ui/ds/tooltip/tooltip.cljs index 159063210b..707540fd95 100644 --- a/frontend/src/app/main/ui/ds/tooltip/tooltip.cljs +++ b/frontend/src/app/main/ui/ds/tooltip/tooltip.cljs @@ -171,7 +171,7 @@ (def ^:private schema:tooltip [:map - [:class {:optional true} :string] + [:class {:optional true} [:maybe :string]] [:id {:optional true} :string] [:offset {:optional true} :int] [:delay {:optional true} :int] @@ -184,6 +184,7 @@ [{:keys [class id children content placement offset delay] :rest props}] (let [internal-id (mf/use-id) + trigger-ref (mf/use-ref nil) id (d/nilv id internal-id) @@ -204,19 +205,23 @@ (mf/use-fn (mf/deps id placement offset) (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 - (fn [] - (let [new-placement (update-tooltip-position tooltip placement origin-brect offset)] - (when (not= new-placement placement) - (reset! placement* new-placement))))] + (let [current (dom/get-current-target event) + related (dom/get-related-target event) + is-node? (fn [node] (and node (.-nodeType node)))] + (when-not (and related (is-node? related) (.contains current related)) + (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 (mf/use-fn @@ -252,6 +257,7 @@ :on-focus on-show :on-blur on-hide :on-key-down handle-key-down + :ref trigger-ref :class [class (stl/css :tooltip-trigger)] :aria-describedby id}) content