🐛 Fix tooltip position on absolute positioned elements (#8509)

* 🐛 Fix tooltip position on absolute positioned elements

* 🐛 Fix tests
This commit is contained in:
Eva Marco 2026-03-09 12:11:39 +01:00 committed by GitHub
parent 0ceadada35
commit c59cc4dff4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 176 additions and 129 deletions

View File

@ -94,7 +94,7 @@ test("Create a LINEAR gradient", async ({ page }) => {
await expect(inputOpacityGlobal).toBeVisible();
await expect(
workspacePage.page.getByText("Linear gradient").nth(1),
workspacePage.page.getByText("Linear gradient")
).toBeVisible();
});
@ -178,7 +178,7 @@ test("Create a RADIAL gradient", async ({ page }) => {
await expect(inputOpacityGlobal).toBeVisible();
await expect(
workspacePage.page.getByText("Radial gradient").nth(1),
workspacePage.page.getByText("Radial gradient")
).toBeVisible();
});

View File

@ -83,7 +83,7 @@ test.describe("Tokens: Apply token", () => {
await brTokenPillSM.click();
// Change token from dropdown
const brTokenOptionXl = borderRadiusSection.getByLabel("borderRadius.xl");
const brTokenOptionXl = borderRadiusSection.getByRole('option', { name: 'borderRadius.xl' })
await expect(brTokenOptionXl).toBeVisible();
await brTokenOptionXl.click();
@ -149,7 +149,7 @@ test.describe("Tokens: Apply token", () => {
await detachButton.click();
// Open dropdown from input
const dropdownBtn = layerMenuSection.getByLabel("Open token list");
const dropdownBtn = layerMenuSection.getByRole('button', { name: 'Open token list' })
await expect(dropdownBtn).toBeVisible();
await dropdownBtn.click();
@ -225,8 +225,8 @@ test.describe("Tokens: Apply token", () => {
await expect(firstShadowFields).toBeVisible();
// Fill in the shadow values
const offsetXInput = firstShadowFields.getByLabel("X");
const offsetYInput = firstShadowFields.getByLabel("Y");
const offsetXInput = firstShadowFields.getByRole('textbox', { name: 'X' });
const offsetYInput = firstShadowFields.getByRole('textbox', { name: 'Y' });
const blurInput = firstShadowFields.getByRole("textbox", {
name: "Blur",
});
@ -299,8 +299,8 @@ test.describe("Tokens: Apply token", () => {
await expect(thirdShadowFields).toBeVisible();
// User adds values for the third shadow
const thirdOffsetXInput = thirdShadowFields.getByLabel("X");
const thirdOffsetYInput = thirdShadowFields.getByLabel("Y");
const thirdOffsetXInput = thirdShadowFields.getByRole('textbox', { name: 'X' });
const thirdOffsetYInput = thirdShadowFields.getByRole('textbox', { name: 'Y' });
const thirdBlurInput = thirdShadowFields.getByRole("textbox", {
name: "Blur",
});
@ -328,10 +328,10 @@ test.describe("Tokens: Apply token", () => {
// Verify that the first shadow kept its values
const firstOffsetXValue = await firstShadowFields
.getByLabel("X")
.getByRole('textbox', { name: 'X' })
.inputValue();
const firstOffsetYValue = await firstShadowFields
.getByLabel("Y")
.getByRole('textbox', { name: 'Y' })
.inputValue();
const firstBlurValue = await firstShadowFields
.getByRole("textbox", { name: "Blur" })
@ -357,10 +357,10 @@ test.describe("Tokens: Apply token", () => {
await expect(newSecondShadowFields).toBeVisible();
const secondOffsetXValue = await newSecondShadowFields
.getByLabel("X")
.getByRole('textbox', { name: 'X' })
.inputValue();
const secondOffsetYValue = await newSecondShadowFields
.getByLabel("Y")
.getByRole('textbox', { name: 'Y' })
.inputValue();
const secondBlurValue = await newSecondShadowFields
.getByRole("textbox", { name: "Blur" })
@ -410,10 +410,10 @@ test.describe("Tokens: Apply token", () => {
// Verify first shadow values are still there
const restoredFirstOffsetX = await firstShadowFields
.getByLabel("X")
.getByRole('textbox', { name: 'X' })
.inputValue();
const restoredFirstOffsetY = await firstShadowFields
.getByLabel("Y")
.getByRole('textbox', { name: 'Y' })
.inputValue();
const restoredFirstBlur = await firstShadowFields
.getByRole("textbox", { name: "Blur" })
@ -433,10 +433,10 @@ test.describe("Tokens: Apply token", () => {
// Verify second shadow values are still there
const restoredSecondOffsetX = await newSecondShadowFields
.getByLabel("X")
.getByRole('textbox', { name: 'X' })
.inputValue();
const restoredSecondOffsetY = await newSecondShadowFields
.getByLabel("Y")
.getByRole('textbox', { name: 'Y' })
.inputValue();
const restoredSecondBlur = await newSecondShadowFields
.getByRole("textbox", { name: "Blur" })
@ -518,7 +518,7 @@ test.describe("Tokens: Apply token", () => {
await dimensionSMTokenPill.nth(1).click();
// Change token from dropdown
const dimensionTokenOptionXl = measuresSection.getByLabel("dimension.xl");
const dimensionTokenOptionXl = measuresSection.getByRole('option', { name: 'dimension.xl' })
await expect(dimensionTokenOptionXl).toBeVisible();
await dimensionTokenOptionXl.click();
@ -572,7 +572,7 @@ test.describe("Tokens: Apply token", () => {
await dimensionSMTokenPill.click();
// Change token from dropdown
const dimensionTokenOptionXl = measuresSection.getByLabel("dimension.xl");
const dimensionTokenOptionXl = measuresSection.getByRole('option', { name: 'dimension.xl' });
await expect(dimensionTokenOptionXl).toBeVisible();
await dimensionTokenOptionXl.click();
@ -626,7 +626,7 @@ test.describe("Tokens: Apply token", () => {
await dimensionSMTokenPill.click();
// Change token from dropdown
const dimensionTokenOptionXl = measuresSection.getByLabel("dimension.xl");
const dimensionTokenOptionXl = measuresSection.getByRole('option', { name: 'dimension.xl' });
await expect(dimensionTokenOptionXl).toBeVisible();
await dimensionTokenOptionXl.click();
@ -682,7 +682,7 @@ test.describe("Tokens: Apply token", () => {
// Change token from dropdown
const dimensionTokenOptionXl =
borderRadiusSection.getByLabel("dimension.xl");
borderRadiusSection.getByRole('option', { name: 'dimension.xl' });
await expect(dimensionTokenOptionXl).toBeVisible();
await dimensionTokenOptionXl.click();
@ -751,7 +751,7 @@ test.describe("Tokens: Apply token", () => {
});
await tokenDropdown.click();
const widthOptionSmall = firstStrokeRow.getByLabel("width-small");
const widthOptionSmall = firstStrokeRow.getByRole('option', { name: 'width-small' });
await expect(widthOptionSmall).toBeVisible();
await widthOptionSmall.click();
const StrokeWidthPillSmall = firstStrokeRow.getByRole("button", {
@ -831,15 +831,10 @@ test.describe("Tokens: Apply token", () => {
});
await detachButton.click();
await expect(marginPillXL).not.toBeVisible();
const horizontalMarginInput = layoutItemSectionSidebar.getByText(
"Horizontal marginOpen token",
);
await expect(horizontalMarginInput).toBeVisible();
const tokenDropdown = horizontalMarginInput.getByRole("button", {
const horizontalMarginInput = layoutItemSectionSidebar.getByRole("button", {
name: "Open token list",
});
await tokenDropdown.click();
await horizontalMarginInput.nth(1).click();
await expect(dimensionTokenOptionXl).toBeVisible();
await dimensionTokenOptionXl.click();

View File

@ -1024,7 +1024,7 @@ test.describe("Tokens - creation", () => {
const nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill("typography.empty");
const valueField = tokensUpdateCreateModal.getByLabel("Font Size");
const valueField = tokensUpdateCreateModal.getByRole("textbox", {name: "Font Size"});
// Insert a value and then delete it
await valueField.fill("1");
@ -1716,12 +1716,12 @@ test.describe("Tokens tab - edition", () => {
// Fill font-family to verify to verify that input value doesn't get split into list of characters
const fontFamilyField = tokensUpdateCreateModal
.getByLabel("Font family")
.getByRole("textbox", { name: "Font family" })
.first();
await fontFamilyField.fill("OneWord");
// Invalidate incorrect values for font size
const fontSizeField = tokensUpdateCreateModal.getByLabel(/Font Size/i);
const fontSizeField = tokensUpdateCreateModal.getByRole("textbox", { name: "Font Size" });
await fontSizeField.fill("invalid");
await expect(
tokensUpdateCreateModal.getByText(/Invalid token value:/),
@ -1736,13 +1736,13 @@ test.describe("Tokens tab - edition", () => {
await fontSizeField.fill("16");
await expect(saveButton).toBeEnabled();
const fontWeightField = tokensUpdateCreateModal.getByLabel(/Font Weight/i);
const fontWeightField = tokensUpdateCreateModal.getByRole("textbox", { name: "Font Weight" });
const letterSpacingField =
tokensUpdateCreateModal.getByLabel(/Letter Spacing/i);
const lineHeightField = tokensUpdateCreateModal.getByLabel(/Line Height/i);
const textCaseField = tokensUpdateCreateModal.getByLabel(/Text Case/i);
tokensUpdateCreateModal.getByRole("textbox", { name: "Letter Spacing" });
const lineHeightField = tokensUpdateCreateModal.getByRole("textbox", { name: "Line Height" });
const textCaseField = tokensUpdateCreateModal.getByRole("textbox", { name: "Text Case" });
const textDecorationField =
tokensUpdateCreateModal.getByLabel(/Text Decoration/i);
tokensUpdateCreateModal.getByRole("textbox", { name: "Text Decoration" });
// Capture all values before switching tabs
const originalValues = {
@ -1800,6 +1800,7 @@ test.describe("Tokens tab - edition", () => {
const colorToken = tokensSidebar.getByRole("button", {
name: "100",
});
await expect(colorToken).toBeVisible();
await colorToken.click({ button: "right" });

View File

@ -33,6 +33,8 @@
(let [variant
(d/nilv variant "primary")
button-ref (mf/use-ref nil)
tooltip-id
(mf/use-id)
@ -47,10 +49,12 @@
props
(mf/spread-props props
{:class [class button-class]
:ref button-ref
:aria-labelledby tooltip-id})]
[:> tooltip* {:content aria-label
:class tooltip-class
:trigger-ref button-ref
:placement tooltip-placement
:id tooltip-id}
[:> :button props

View File

@ -28,7 +28,8 @@
{::mf/schema schema:token-option}
[{:keys [id name on-click selected ref focused resolved] :rest props}]
(let [internal-id (mf/use-id)
id (d/nilv id internal-id)]
id (d/nilv id internal-id)
element-ref (mf/use-ref nil)]
[:li {:value id
:class (stl/css-case :token-option true
:option-with-pill true
@ -50,10 +51,12 @@
:aria-hidden (when name true)}]
[:span {:class (stl/css :icon-placeholder)}])
[:> tooltip* {:content name
:trigger-ref element-ref
:id (dm/str id "-name")
:class (stl/css :option-text)}
;; Add ellipsis
[:span {:aria-labelledby (dm/str id "-name")}
;; Add ellipsis
[:span {:aria-labelledby (dm/str id "-name")
:ref element-ref}
name]]
(when resolved
[:> :span {:class (stl/css :option-pill)}

View File

@ -84,6 +84,7 @@
:on-click on-icon-click}])
(if aria-label
[:> tooltip* {:content aria-label
:trigger-ref (or ref input-ref)
:class (stl/css :tooltip-wrapper)
:id tooltip-id}
[:> "input" props]]

View File

@ -43,6 +43,7 @@
(tr "ds.inputs.token-field.no-active-token-option"))
default-id (mf/use-id)
id (d/nilv id default-id)
pill-ref (mf/use-ref nil)
focus-wrapper
(mf/use-fn
@ -53,6 +54,7 @@
(dom/focus! (mf/ref-val token-wrapper-ref)))))]
[:> tooltip* {:content property
:class (stl/css :token-field-wrapper)
:trigger-ref token-wrapper-ref
:id (dm/str default-id "-input")}
[:div {:class [class (stl/css-case :token-field true
:with-icon (some? slot-start)
@ -70,8 +72,10 @@
[:div {:class (stl/css :content-wrapper)}
[:> tooltip* {:content content
:trigger-ref pill-ref
:id (dm/str id "-pill")}
[:button {:on-click on-click
:ref pill-ref
:class (stl/css-case :pill true
:no-set-pill (not set-active?)
:pill-disabled disabled)

View File

@ -6,7 +6,6 @@
(ns app.main.ui.ds.tooltip.tooltip
(:require-macros
[app.common.data.macros :as dm]
[app.main.style :as stl])
(:require
[app.common.data :as d]
@ -15,10 +14,10 @@
[app.util.timers :as ts]
[rumext.v2 :as mf]))
(def ^:private ^:const arrow-height 12)
(def ^:private ^:const half-arrow-height (/ arrow-height 2))
(def ^:private ^:const overlay-offset 32)
(defonce active-tooltip (atom nil))
(defn- clear-schedule
[ref]
(when-let [schedule (mf/ref-val ref)]
@ -29,20 +28,6 @@
[ref delay f]
(mf/set-ref-val! ref (ts/schedule delay f)))
(defn- show-popover
[node]
(when (.-isConnected ^js node)
(.showPopover ^js node)))
(defn- hide-popover
[node]
(when (and (some? node)
(fn? (.-hidePopover node)))
(dom/unset-css-property! node "block-size")
(dom/unset-css-property! node "inset-block-start")
(dom/unset-css-property! node "inset-inline-start")
(.hidePopover ^js node)))
(defn- calculate-placement-bounding-rect
"Given a placement, calcultates the bounding rect for it taking in
account provided tooltip bounding rect and the origin bounding
@ -72,18 +57,18 @@
:height tooltip-height}
"left"
{:top (- (+ trigger-top (/ trigger-height 2) half-arrow-height) (/ tooltip-height 2))
:left (- trigger-left tooltip-width arrow-height)
{:top (- (+ trigger-top (/ trigger-height 2)) (/ tooltip-height 2))
:left (- trigger-left tooltip-width)
:right (+ (- trigger-left tooltip-width) tooltip-width)
:bottom (+ (- (+ trigger-top (/ trigger-height 2) half-arrow-height) (/ tooltip-height 2)) tooltip-height)
:bottom (+ (- (+ trigger-top (/ trigger-height 2)) (/ tooltip-height 2)) tooltip-height)
:width tooltip-width
:height tooltip-height}
"right"
{:top (- (+ trigger-top (/ trigger-height 2) half-arrow-height) (/ tooltip-height 2))
{:top (- (+ trigger-top (/ trigger-height 2)) (/ tooltip-height 2))
:left (+ trigger-right offset)
:right (+ trigger-right offset tooltip-width)
:bottom (+ (- (+ trigger-top (/ trigger-height 2) half-arrow-height) (/ tooltip-height 2)) tooltip-height)
:bottom (+ (- (+ trigger-top (/ trigger-height 2)) (/ tooltip-height 2)) tooltip-height)
:width tooltip-width
:height tooltip-height}
@ -153,22 +138,6 @@
(recur (rest placements))
#js [placement placement-brect])))))
(defn- update-tooltip-position
"Update the tooltip position having in account the current window
size, placement. It calculates the appropriate placement and updates
the dom with the result."
[tooltip placement origin-brect offset]
(show-popover tooltip)
(let [tooltip-brect (dom/get-bounding-rect tooltip)
tooltip-brect (assoc tooltip-brect :height (:height tooltip-brect) :width (:width tooltip-brect))
window-size (dom/get-window-size)]
(when-let [[placement placement-rect] (find-matching-placement placement tooltip-brect origin-brect window-size offset)]
(let [height (:height placement-rect)]
(dom/set-css-property! tooltip "block-size" (dm/str height "px"))
(dom/set-css-property! tooltip "inset-block-start" (dm/str (:top placement-rect) "px"))
(dom/set-css-property! tooltip "inset-inline-start" (dm/str (:left placement-rect) "px")))
placement)))
(def ^:private schema:tooltip
[:map
[:class {:optional true} [:maybe :string]]
@ -176,19 +145,26 @@
[:offset {:optional true} :int]
[:delay {:optional true} :int]
[:content [:or fn? :string map?]]
[:trigger-ref {:optional true} [:maybe :any]]
[:placement {:optional true}
[:maybe [:enum "top" "bottom" "left" "right" "top-right" "bottom-right" "bottom-left" "top-left"]]]])
(mf/defc tooltip*
{::mf/schema schema:tooltip}
[{:keys [class id children content placement offset delay] :rest props}]
[{:keys [class id children content placement offset delay trigger-ref aria-label] :rest props}]
(let [internal-id
(mf/use-id)
trigger-ref (mf/use-ref nil)
internal-trigger-ref (mf/use-ref nil)
trigger-ref (or trigger-ref internal-trigger-ref)
tooltip-ref (mf/use-ref nil)
id
(d/nilv id internal-id)
tooltip-id
(mf/use-id)
placement*
(mf/use-state #(d/nilv placement "top"))
@ -201,35 +177,35 @@
schedule-ref
(mf/use-ref nil)
visible*
(mf/use-state false)
visible (deref visible*)
on-show
(mf/use-fn
(mf/deps id placement offset)
(fn [event]
(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))
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)))))))
(mf/deps tooltip-id delay)
(fn [_]
(let [trigger-el (mf/ref-val trigger-ref)]
(clear-schedule schedule-ref)
(add-schedule schedule-ref (d/nilv delay 300)
(fn []
(prn tooltip-id)
(when-let [active @active-tooltip]
(when (not= (:id active) tooltip-id)
(when-let [tooltip-el (dom/get-element (:id active))]
(dom/set-css-property! tooltip-el "display" "none"))
(reset! active-tooltip nil)))
(reset! active-tooltip {:id tooltip-id :trigger trigger-el})
(reset! visible* true))))))
on-hide
(mf/use-fn
(mf/deps id)
(mf/deps tooltip-id)
(fn []
(when-let [tooltip (dom/get-element id)]
(clear-schedule schedule-ref)
(hide-popover tooltip))))
(clear-schedule schedule-ref)
(reset! visible* false)
(when (= (:id @active-tooltip) tooltip-id)
(reset! active-tooltip nil))))
handle-key-down
(mf/use-fn
@ -250,28 +226,62 @@
:tooltip-bottom-left (identical? placement "bottom-left")
:tooltip-top-left (identical? placement "top-left"))
content
(if (fn? content)
(content)
content)
props
(mf/spread-props props
{:on-mouse-enter on-show
:on-mouse-leave on-hide
:on-focus on-show
:on-blur on-hide
:ref internal-trigger-ref
:on-key-down handle-key-down
:ref trigger-ref
:id id
:class [class (stl/css :tooltip-trigger)]
:aria-describedby id})
content
(if (fn? content)
(content)
content)]
:aria-label (if (string? content)
content
aria-label)})]
(mf/use-effect
(mf/deps visible placement offset)
(fn []
(when visible
(let [trigger-el (mf/ref-val trigger-ref)
tooltip-el (mf/ref-val tooltip-ref)]
(when (and trigger-el tooltip-el)
(js/requestAnimationFrame
(fn []
(let [origin-brect (dom/get-bounding-rect trigger-el)
tooltip-brect (dom/get-bounding-rect tooltip-el)
window-size (dom/get-window-size)]
(when-let [[new-placement placement-rect]
(find-matching-placement
placement
tooltip-brect
origin-brect
window-size
offset)]
(dom/set-css-property! tooltip-el "inset-block-start"
(str (:top placement-rect) "px"))
(dom/set-css-property! tooltip-el "inset-inline-start"
(str (:left placement-rect) "px"))
(when (not= new-placement placement)
(reset! placement* new-placement)))))))))))
[:> :div props
children
[:div {:class (stl/css :tooltip)
:id id
:popover "auto"
:role "tooltip"}
[:div {:class tooltip-class}
[:div {:class (stl/css :tooltip-content)} content]
[:div {:class (stl/css :tooltip-arrow)
:id "tooltip-arrow"}]]]]))
(when visible
(mf/portal
(mf/html
[:div {:class (stl/css :tooltip)
:role "tooltip"
:id tooltip-id
:ref tooltip-ref}
[:div {:class tooltip-class}
[:div {:class (stl/css :tooltip-content)} content]
[:div {:class (stl/css :tooltip-arrow)
:id "tooltip-arrow"}]]])
(.-body js/document)))]))

View File

@ -6,17 +6,19 @@
@use "ds/_sizes.scss" as *;
@use "ds/_borders.scss" as *;
@use "ds/z-index.scss" as *;
@use "ds/typography.scss" as t;
$arrow-side: 12px;
.tooltip {
position: absolute;
position: fixed;
max-inline-size: $sz-352;
background-color: transparent;
overflow: hidden;
inline-size: fit-content;
block-size: fit-content;
z-index: var(--z-index-notifications);
}
.tooltip-content-wrapper {

View File

@ -96,8 +96,9 @@
image (:image background)
format (if id? "rounded" "square")
element-id (mf/use-id)
has-opacity? (and (some? (:color background))
(< (:opacity background) 1))
has-opacity? (and (some? (:color background))
(< (:opacity background) 1))
element-ref (mf/use-ref nil)
on-click
(mf/use-fn
(mf/deps background on-click)
@ -120,7 +121,8 @@
(mf/spread-props props {:class class
:on-click on-click
:type button-type
:aria-labelledby element-id})
:aria-labelledby element-id
:ref element-ref})
children (mf/html
[:> element-type props
(cond
@ -147,6 +149,7 @@
[:> tooltip* {:content (if tooltip-content
tooltip-content
(color-title background))
:trigger-ref element-ref
:id element-id}
children]

View File

@ -23,11 +23,12 @@
(mf/defc property-detail-copiable*
{::mf/schema schema:property-detail-copiable}
[{:keys [color token copied on-click children]}]
[{:keys [color token copied on-click children ref]}]
[:button {:class (stl/css-case :property-detail-copiable true
:property-detail-copied copied
:property-detail-copiable-color (some? color))
:on-click on-click}
:on-click on-click
:ref ref}
(when color
[:> swatch* {:background color
:size "small"}])

View File

@ -41,6 +41,7 @@
color-image-name (:name color-image)
color-image-url (when (some? color-image)
(cfg/resolve-file-media color-image))
row-ref (mf/use-ref nil)
color-opacity (mf/use-memo
(mf/deps color)
#(dm/str (-> color
@ -96,6 +97,7 @@
(if token
[:> tooltip* {:id (:name token)
:class (stl/css :tooltip-token-wrapper)
:trigger-ref row-ref
:content #(mf/html
[:div {:class (stl/css :tooltip-token)}
[:div {:class (stl/css :tooltip-token-title)}
@ -104,6 +106,7 @@
(:resolved-value token)]])}
[:> property-detail-copiable* {:color color
:token token
:ref row-ref
:copied copied
:on-click copy-attr} formatted-color-value]]

View File

@ -37,6 +37,7 @@
copiable-value (if (some? token)
(:name token)
property)
row-ref (mf/use-ref nil)
copy-attr
(mf/use-fn
@ -54,6 +55,7 @@
(let [token-type (:type token)]
[:> tooltip* {:id (:name token)
:class (stl/css :tooltip-token-wrapper)
:trigger-ref row-ref
:content #(mf/html
[:div {:class (stl/css :tooltip-token)}
[:div {:class (stl/css :tooltip-token-title)}
@ -75,6 +77,7 @@
(:resolved-value token))]])}
[:> property-detail-copiable* {:token token
:copied copied
:ref row-ref
:on-click copy-attr} detail]])
[:> property-detail-copiable* {:copied copied
:on-click copy-attr} detail])

View File

@ -44,12 +44,15 @@
(on-token-pill-click event token)))
id-tooltip (mf/use-id)
resolved (:resolved-value token)
color-value (dwta/value->color resolved)]
color-value (dwta/value->color resolved)
item-ref (mf/use-ref nil)]
[:> tooltip* {:id id-tooltip
:style {:width "100%"}
:trigger-ref item-ref
:content (:name token)}
[:button {:class (stl/css-case :color-token-item true
:color-token-selected selected)
:ref item-ref
:aria-labelledby id-tooltip
:on-click on-click}
[:> swatch* {:background color-value

View File

@ -94,6 +94,7 @@
not-active (or (empty? active-tokens)
(nil? token))
id (dm/str (:id token) "-name")
token-name-ref (mf/use-ref nil)
swatch-tooltip-content (cond
not-active
(tr "ds.inputs.token-field.no-active-token-option")
@ -126,8 +127,11 @@
:size "small"}]]
[:> tooltip* {:content name-tooltip-content
:id id
:aria-label (str (tr "workspace.tokens.token-name") ": " applied-token-name)
:trigger-ref token-name-ref
:class (stl/css :token-tooltip)}
[:div {:class (stl/css :token-name)
:ref token-name-ref
:aria-labelledby id}
(or token-name applied-token-name)]]
[:div {:class (stl/css :token-actions)}

View File

@ -4,17 +4,27 @@
//
// Copyright (c) KALEIDOS INC
@use "refactor/common-refactor.scss" as deprecated;
@use "ds/_sizes.scss" as *;
@use "ds/_borders.scss" as *;
@use "ds/_utils.scss" as *;
@use "ds/z-index.scss" as *;
.token-modal-wrapper {
@extend .modal-container-base;
@include deprecated.menuShadow;
border-radius: $br-4;
background-color: var(--color-background-primary);
border: $b-2 solid var(--color-background-quaternary);
min-width: $sz-364;
min-height: $sz-192;
max-width: $sz-512;
max-height: $sz-512;
box-shadow: 0px 0px $sz-12 0px var(--color-shadow-dark);
position: absolute;
width: auto;
min-width: auto;
z-index: 11;
z-index: var(--z-index-set);
overflow-y: auto;
overflow-x: hidden;
padding: var(--sp-xxxl);
&.token-modal-large {
max-block-size: 95vh;
}
@ -22,6 +32,6 @@
.close-btn {
position: absolute;
top: deprecated.$s-6;
right: deprecated.$s-6;
top: px2rem(6);
right: px2rem(6);
}