mirror of
https://github.com/penpot/penpot.git
synced 2025-06-14 11:11:38 +02:00
♻️ Update button-icon with tooltip component (#6539)
* 🐛 Add tooltip to base icon button * 🎉 Update id prop * 🐛 Fix test
This commit is contained in:
parent
55997a3d4a
commit
a2abaea637
10 changed files with 60 additions and 39 deletions
|
@ -40,6 +40,7 @@ test("Create a LINEAR gradient", async ({ page }) => {
|
||||||
fileId: "6191cd35-bb1f-81f7-8004-7cc63d087374",
|
fileId: "6191cd35-bb1f-81f7-8004-7cc63d087374",
|
||||||
pageId: "6191cd35-bb1f-81f7-8004-7cc63d087375",
|
pageId: "6191cd35-bb1f-81f7-8004-7cc63d087375",
|
||||||
});
|
});
|
||||||
|
|
||||||
await workspacePage.clickLeafLayer("Rectangle");
|
await workspacePage.clickLeafLayer("Rectangle");
|
||||||
|
|
||||||
const swatch = workspacePage.page.getByRole("button", { name: "#B1B2B5" });
|
const swatch = workspacePage.page.getByRole("button", { name: "#B1B2B5" });
|
||||||
|
@ -74,17 +75,21 @@ test("Create a LINEAR gradient", async ({ page }) => {
|
||||||
|
|
||||||
const inputColor2 = workspacePage.colorpicker
|
const inputColor2 = workspacePage.colorpicker
|
||||||
.getByPlaceholder("Mixed")
|
.getByPlaceholder("Mixed")
|
||||||
.nth(1);
|
.nth(2);
|
||||||
await inputColor2.fill("red");
|
await inputColor2.fill("red");
|
||||||
|
|
||||||
const inputOpacity2 = workspacePage.colorpicker.getByPlaceholder("--").nth(1);
|
const inputOpacity2 = workspacePage.colorpicker.getByPlaceholder("--").nth(2);
|
||||||
await inputOpacity2.fill("100");
|
await inputOpacity2.fill("40");
|
||||||
|
|
||||||
const inputOpacityGlobal = workspacePage.page
|
const inputOpacityGlobal = workspacePage.colorpicker.getByTestId(
|
||||||
.locator("div")
|
"opacity-global-input",
|
||||||
.filter({ hasText: /^FillLinear gradient%$/ })
|
);
|
||||||
.getByPlaceholder("--");
|
await inputOpacityGlobal.fill("50");
|
||||||
await inputOpacityGlobal.fill("100");
|
await inputOpacityGlobal.press("Enter");
|
||||||
|
await expect(inputOpacityGlobal).toHaveValue("50");
|
||||||
|
await expect(inputOpacityGlobal).toBeVisible();
|
||||||
|
|
||||||
|
await expect(workspacePage.page.getByText("Linear gradient")).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Create a RADIAL gradient", async ({ page }) => {
|
test("Create a RADIAL gradient", async ({ page }) => {
|
||||||
|
@ -147,8 +152,18 @@ test("Create a RADIAL gradient", async ({ page }) => {
|
||||||
const inputColor2 = workspacePage.page.getByPlaceholder("Mixed").nth(2);
|
const inputColor2 = workspacePage.page.getByPlaceholder("Mixed").nth(2);
|
||||||
await inputColor2.fill("red");
|
await inputColor2.fill("red");
|
||||||
|
|
||||||
const inputOpacity2 = workspacePage.colorpicker.getByPlaceholder("--").nth(1);
|
const inputOpacity2 = workspacePage.colorpicker.getByPlaceholder("--").nth(2);
|
||||||
await inputOpacity2.fill("100");
|
await inputOpacity2.fill("100");
|
||||||
|
|
||||||
|
const inputOpacityGlobal = workspacePage.colorpicker.getByTestId(
|
||||||
|
"opacity-global-input",
|
||||||
|
);
|
||||||
|
await inputOpacityGlobal.fill("50");
|
||||||
|
await inputOpacityGlobal.press("Enter");
|
||||||
|
await expect(inputOpacityGlobal).toHaveValue("50");
|
||||||
|
await expect(inputOpacityGlobal).toBeVisible();
|
||||||
|
|
||||||
|
await expect(workspacePage.page.getByText("Radial gradient")).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Gradient stops limit", async ({ page }) => {
|
test("Gradient stops limit", async ({ page }) => {
|
||||||
|
|
|
@ -92,7 +92,9 @@ test.describe("Tokens: Tokens Tab", () => {
|
||||||
await setupEmptyTokensFile(page);
|
await setupEmptyTokensFile(page);
|
||||||
|
|
||||||
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
|
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
|
||||||
await tokensTabPanel.getByTitle("Add token: Color").click();
|
await tokensTabPanel
|
||||||
|
.getByRole("button", { name: "Add Token: Color" })
|
||||||
|
.click();
|
||||||
|
|
||||||
// Create color token with mouse
|
// Create color token with mouse
|
||||||
|
|
||||||
|
@ -129,7 +131,9 @@ test.describe("Tokens: Tokens Tab", () => {
|
||||||
|
|
||||||
// Create token referencing the previous one with keyboard
|
// Create token referencing the previous one with keyboard
|
||||||
|
|
||||||
await tokensTabPanel.getByTitle("Add token: Color").click();
|
await tokensTabPanel
|
||||||
|
.getByRole("button", { name: "Add Token: Color" })
|
||||||
|
.click();
|
||||||
await expect(tokensUpdateCreateModal).toBeVisible();
|
await expect(tokensUpdateCreateModal).toBeVisible();
|
||||||
|
|
||||||
await nameField.click();
|
await nameField.click();
|
||||||
|
@ -171,7 +175,9 @@ test.describe("Tokens: Tokens Tab", () => {
|
||||||
await setupEmptyTokensFile(page);
|
await setupEmptyTokensFile(page);
|
||||||
|
|
||||||
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
|
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
|
||||||
await tokensTabPanel.getByTitle("Add token: Dimensions").click();
|
await tokensTabPanel
|
||||||
|
.getByRole("button", { name: "Add token: Dimensions" })
|
||||||
|
.click();
|
||||||
|
|
||||||
await expect(tokensUpdateCreateModal).toBeVisible();
|
await expect(tokensUpdateCreateModal).toBeVisible();
|
||||||
|
|
||||||
|
@ -351,7 +357,9 @@ test.describe("Tokens: Tokens Tab", () => {
|
||||||
await setupEmptyTokensFile(page);
|
await setupEmptyTokensFile(page);
|
||||||
|
|
||||||
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
|
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
|
||||||
await tokensTabPanel.getByTitle("Add token: Color").click();
|
await tokensTabPanel
|
||||||
|
.getByRole("button", { name: "Add Token: Color" })
|
||||||
|
.click();
|
||||||
|
|
||||||
// Create grouped color token with mouse
|
// Create grouped color token with mouse
|
||||||
|
|
||||||
|
@ -382,7 +390,9 @@ test.describe("Tokens: Tokens Tab", () => {
|
||||||
await setupEmptyTokensFile(page);
|
await setupEmptyTokensFile(page);
|
||||||
|
|
||||||
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
|
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
|
||||||
await tokensTabPanel.getByTitle("Add token: Color").click();
|
await tokensTabPanel
|
||||||
|
.getByRole("button", { name: "Add Token: Color" })
|
||||||
|
.click();
|
||||||
|
|
||||||
await expect(tokensUpdateCreateModal).toBeVisible();
|
await expect(tokensUpdateCreateModal).toBeVisible();
|
||||||
const nameField = tokensUpdateCreateModal.getByLabel("Name");
|
const nameField = tokensUpdateCreateModal.getByLabel("Name");
|
||||||
|
|
|
@ -22,7 +22,7 @@ test("Group bubbles when zooming out if they overlap", async ({ page }) => {
|
||||||
const zoom = page.getByTitle("Zoom");
|
const zoom = page.getByTitle("Zoom");
|
||||||
await zoom.click();
|
await zoom.click();
|
||||||
|
|
||||||
const zoomOut = page.getByTitle("Zoom out");
|
const zoomOut = page.getByRole("button", { name: "Zoom out" });
|
||||||
await zoomOut.click();
|
await zoomOut.click();
|
||||||
await zoomOut.click();
|
await zoomOut.click();
|
||||||
await zoomOut.click();
|
await zoomOut.click();
|
||||||
|
|
|
@ -18,7 +18,7 @@ test("User haven't toolbar", async ({ page }) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("User haven't edition menu entries", async ({ page }) => {
|
test("User haven't edition menu entries", async ({ page }) => {
|
||||||
await page.getByTitle("main menu").click();
|
await page.getByRole("button", { name: "Main menu" }).click();
|
||||||
await page.getByText("file").last().click();
|
await page.getByText("file").last().click();
|
||||||
|
|
||||||
await expect(page.getByText("Add as Shared Library")).toBeHidden();
|
await expect(page.getByText("Add as Shared Library")).toBeHidden();
|
||||||
|
|
|
@ -294,7 +294,7 @@ test("User have edition menu entries", async ({ page }) => {
|
||||||
await workspacePage.setupEmptyFile(page);
|
await workspacePage.setupEmptyFile(page);
|
||||||
await workspacePage.goToWorkspace();
|
await workspacePage.goToWorkspace();
|
||||||
|
|
||||||
await page.getByTitle("Main menu").click();
|
await page.getByRole("button", { name: "Main menu" }).click();
|
||||||
await page.getByText("file").last().click();
|
await page.getByText("file").last().click();
|
||||||
|
|
||||||
await expect(page.getByText("Add as Shared Library")).toBeVisible();
|
await expect(page.getByText("Add as Shared Library")).toBeVisible();
|
||||||
|
@ -390,7 +390,7 @@ test("[Taiga #9930] Zoom fit all doesn't fits all", async ({
|
||||||
const zoom = await page.getByTitle("Zoom");
|
const zoom = await page.getByTitle("Zoom");
|
||||||
await zoom.click();
|
await zoom.click();
|
||||||
|
|
||||||
const zoomIn = await page.getByTitle("Zoom in");
|
const zoomIn = await page.getByRole("button", { name: "Zoom in" });
|
||||||
await zoomIn.click();
|
await zoomIn.click();
|
||||||
await zoomIn.click();
|
await zoomIn.click();
|
||||||
await zoomIn.click();
|
await zoomIn.click();
|
||||||
|
|
|
@ -10,13 +10,13 @@
|
||||||
[app.main.style :as stl])
|
[app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]]
|
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]]
|
||||||
|
[app.main.ui.ds.tooltip.tooltip :refer [tooltip*]]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(def ^:private schema:icon-button
|
(def ^:private schema:icon-button
|
||||||
[:map
|
[:map
|
||||||
[:class {:optional true} :string]
|
[:class {:optional true} :string]
|
||||||
[:icon-class {:optional true} :string]
|
[:icon-class {:optional true} :string]
|
||||||
[:tooltip-id {:optional true} :string]
|
|
||||||
[:icon
|
[:icon
|
||||||
[:and :string [:fn #(contains? icon-list %)]]]
|
[:and :string [:fn #(contains? icon-list %)]]]
|
||||||
[:aria-label :string]
|
[:aria-label :string]
|
||||||
|
@ -25,18 +25,17 @@
|
||||||
|
|
||||||
(mf/defc icon-button*
|
(mf/defc icon-button*
|
||||||
{::mf/schema schema:icon-button}
|
{::mf/schema schema:icon-button}
|
||||||
[{:keys [class icon icon-class variant aria-label children tooltip-id] :rest props}]
|
[{:keys [class icon icon-class variant aria-label children] :rest props}]
|
||||||
(let [variant (or variant "primary")
|
(let [variant (or variant "primary")
|
||||||
|
tooltip-id (mf/use-id)
|
||||||
class (dm/str class " " (stl/css-case :icon-button true
|
class (dm/str class " " (stl/css-case :icon-button true
|
||||||
:icon-button-primary (= variant "primary")
|
:icon-button-primary (= variant "primary")
|
||||||
:icon-button-secondary (= variant "secondary")
|
:icon-button-secondary (= variant "secondary")
|
||||||
:icon-button-ghost (= variant "ghost")
|
:icon-button-ghost (= variant "ghost")
|
||||||
:icon-button-action (= variant "action")
|
:icon-button-action (= variant "action")
|
||||||
:icon-button-destructive (= variant "destructive")))
|
:icon-button-destructive (= variant "destructive")))
|
||||||
props (if (some? tooltip-id)
|
props (mf/spread-props props {:class class
|
||||||
(mf/spread-props props {:class class
|
:aria-labelledby tooltip-id})]
|
||||||
:aria-describedby tooltip-id})
|
[:> tooltip* {:tooltip-content aria-label
|
||||||
(mf/spread-props props {:class class
|
:id tooltip-id}
|
||||||
:aria-label aria-label
|
[:> "button" props [:> icon* {:icon-id icon :aria-hidden true :class icon-class}] children]]))
|
||||||
:title aria-label}))]
|
|
||||||
[:> "button" props [:> icon* {:icon-id icon :aria-hidden true :class icon-class}] children]))
|
|
|
@ -42,7 +42,7 @@
|
||||||
|
|
||||||
"left"
|
"left"
|
||||||
{:top (- (+ trigger-top (/ trigger-height 2) half-arrow-height) (/ tooltip-height 2))
|
{:top (- (+ trigger-top (/ trigger-height 2) half-arrow-height) (/ tooltip-height 2))
|
||||||
:left (- trigger-left tooltip-width)
|
:left (- trigger-left tooltip-width arrow-height)
|
||||||
:right (+ (- trigger-left tooltip-width) 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) half-arrow-height) (/ tooltip-height 2)) tooltip-height)
|
||||||
:width tooltip-width
|
:width tooltip-width
|
||||||
|
@ -109,7 +109,7 @@
|
||||||
(def ^:private schema:tooltip
|
(def ^:private schema:tooltip
|
||||||
[:map
|
[:map
|
||||||
[:class {:optional true} :string]
|
[:class {:optional true} :string]
|
||||||
[:id :string]
|
[:id {:optional true} :string]
|
||||||
[:offset {:optional true} :int]
|
[:offset {:optional true} :int]
|
||||||
[:delay {:optional true} :int]
|
[:delay {:optional true} :int]
|
||||||
[:placement {:optional true}
|
[:placement {:optional true}
|
||||||
|
@ -118,7 +118,8 @@
|
||||||
(mf/defc tooltip*
|
(mf/defc tooltip*
|
||||||
{::mf/schema schema:tooltip}
|
{::mf/schema schema:tooltip}
|
||||||
[{:keys [class id children tooltip-content placement offset delay] :rest props}]
|
[{:keys [class id children tooltip-content placement offset delay] :rest props}]
|
||||||
(let [placement* (mf/use-state #(d/nilv placement "top"))
|
(let [id (or id (mf/use-id))
|
||||||
|
placement* (mf/use-state #(d/nilv placement "top"))
|
||||||
placement (deref placement*)
|
placement (deref placement*)
|
||||||
delay (d/nilv delay 300)
|
delay (d/nilv delay 300)
|
||||||
|
|
||||||
|
|
|
@ -420,6 +420,7 @@
|
||||||
{:value (-> data :opacity opacity->string)
|
{:value (-> data :opacity opacity->string)
|
||||||
:on-change handle-change-gradient-opacity
|
:on-change handle-change-gradient-opacity
|
||||||
:default 100
|
:default 100
|
||||||
|
:data-testid "opacity-global-input"
|
||||||
:min 0
|
:min 0
|
||||||
:max 100}]])
|
:max 100}]])
|
||||||
|
|
||||||
|
|
|
@ -336,7 +336,6 @@
|
||||||
[:> icon-button*
|
[:> icon-button*
|
||||||
{:variant "ghost"
|
{:variant "ghost"
|
||||||
:aria-label (tr "workspace.options.fit-content")
|
:aria-label (tr "workspace.options.fit-content")
|
||||||
:title (tr "workspace.options.fit-content")
|
|
||||||
:on-pointer-down handle-fit-content
|
:on-pointer-down handle-fit-content
|
||||||
:icon "fit-content"}]])
|
:icon "fit-content"}]])
|
||||||
(when (options :size)
|
(when (options :size)
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||||
[app.main.ui.ds.foundations.typography.text :refer [text*]]
|
[app.main.ui.ds.foundations.typography.text :refer [text*]]
|
||||||
[app.main.ui.ds.tooltip.tooltip :refer [tooltip*]]
|
|
||||||
[app.main.ui.hooks :as h]
|
[app.main.ui.hooks :as h]
|
||||||
[app.main.ui.hooks.resize :refer [use-resize-hook]]
|
[app.main.ui.hooks.resize :refer [use-resize-hook]]
|
||||||
[app.main.ui.workspace.sidebar.assets.common :as cmm]
|
[app.main.ui.workspace.sidebar.assets.common :as cmm]
|
||||||
|
@ -424,13 +423,10 @@
|
||||||
|
|
||||||
|
|
||||||
(when (contains? cf/flags :token-units)
|
(when (contains? cf/flags :token-units)
|
||||||
[:> tooltip* {:tooltip-content "Tokens settings"
|
|
||||||
:id "button-setting"}
|
|
||||||
[:> icon-button* {:variant "secondary"
|
[:> icon-button* {:variant "secondary"
|
||||||
:icon "settings"
|
:icon "settings"
|
||||||
:tooltip-id "button-setting"
|
|
||||||
:aria-label "Settings"
|
:aria-label "Settings"
|
||||||
:on-click open-settings-modal}]])]))
|
:on-click open-settings-modal}])]))
|
||||||
|
|
||||||
(mf/defc tokens-sidebar-tab*
|
(mf/defc tokens-sidebar-tab*
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue