diff --git a/frontend/playwright/ui/visual-specs/visual-viewer.spec.js b/frontend/playwright/ui/visual-specs/visual-viewer.spec.js index 2085eca3e3..80ed3f7d52 100644 --- a/frontend/playwright/ui/visual-specs/visual-viewer.spec.js +++ b/frontend/playwright/ui/visual-specs/visual-viewer.spec.js @@ -362,3 +362,36 @@ test.describe("Inspect code tab", () => { }); }); }); + +test.describe("Interactions menu", () => { + test("Shows the interactions menu closed and open", async ({ page }) => { + const viewerPage = new ViewerPage(page); + await viewerPage.setupLoggedInUser(); + await viewerPage.setupFileWithMultipleBoards(); + await viewerPage.goToViewer({ + fileId: "dd5cc0bb-91ff-81b9-8004-77df9cd3edb0", + pageId: "dd5cc0bb-91ff-81b9-8004-77df9cd3edb3", + }); + + const trigger = page + .getByText("Interactions", { exact: true }) + .locator(".."); + await expect(trigger).toBeVisible(); + await page.mouse.move(640, 600); + // Closed: the "Interactions" trigger with its arrow. + await expect(trigger).toHaveScreenshot({ + maxDiffPixelRatio: 0, + threshold: 0, + }); + + await trigger.click(); + const menu = page.getByText("Show interactions", { exact: true }); + await expect(menu).toBeVisible(); + await page.mouse.move(640, 600); + // Open: the menu with the selected mode ticked. + await expect(menu.locator("../..")).toHaveScreenshot({ + maxDiffPixelRatio: 0, + threshold: 0, + }); + }); +}); diff --git a/frontend/src/app/main/ui/viewer/interactions.cljs b/frontend/src/app/main/ui/viewer/interactions.cljs index bd96266d37..0aff863b5d 100644 --- a/frontend/src/app/main/ui/viewer/interactions.cljs +++ b/frontend/src/app/main/ui/viewer/interactions.cljs @@ -18,8 +18,8 @@ [app.main.features :as features] [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] + [app.main.ui.ds.foundations.assets.icon :as i :refer [icon*]] [app.main.ui.hooks :as h] - [app.main.ui.icons :as deprecated-icon] [app.main.ui.viewer.shapes :as shapes] [app.main.ui.viewer.viewport-common :as vpc] [app.main.ui.viewer.viewport-wasm :as viewport.wasm] @@ -218,11 +218,17 @@ (st/emit! (dv/go-to-frame (:starting-frame flow))))))] (when flows - [:div {:on-click toggle-dropdown - :class (stl/css :view-options)} - [:span {:class (stl/css :icon)} deprecated-icon/play] - [:span {:class (stl/css :dropdown-title)} (:name current-flow)] - [:span {:class (stl/css :icon-dropdown)} deprecated-icon/arrow] + [:div {:class (stl/css :view-options-wrapper)} + [:button {:type "button" + :class (stl/css :view-options) + :aria-expanded show-dropdown? + :aria-haspopup "menu" + :on-click toggle-dropdown} + [:> icon* {:icon-id i/play :size "s" :class (stl/css :icon)}] + [:span {:class (stl/css :dropdown-title)} (:name current-flow)] + [:> icon* {:icon-id i/arrow-down + :size "s" + :class (stl/css :icon-dropdown)}]] [:& dropdown {:show show-dropdown? :on-close hide-dropdown} [:ul {:class (stl/css :dropdown)} @@ -236,7 +242,7 @@ :on-click select-flow} [:span {:class (stl/css :label)} (:name flow)] (when (= flow-id (:id current-flow)) - [:span {:class (stl/css :icon)} deprecated-icon/tick])])]]]))) + [:> icon* {:icon-id i/tick :size "s" :class (stl/css :icon)}])])]]]))) (mf/defc interactions-menu* [{:keys [interactions-mode]}] @@ -253,10 +259,16 @@ (dom/stop-propagation event) (st/emit! (dv/set-interactions-mode mode)))))] - [:div {:on-click toggle-dropdown - :class (stl/css :view-options)} - [:span {:class (stl/css :dropdown-title)} (tr "viewer.header.interactions")] - [:span {:class (stl/css :icon-dropdown)} deprecated-icon/arrow] + [:div {:class (stl/css :view-options-wrapper)} + [:button {:type "button" + :class (stl/css :view-options) + :aria-expanded (deref show-dropdown?) + :aria-haspopup "menu" + :on-click toggle-dropdown} + [:span {:class (stl/css :dropdown-title)} (tr "viewer.header.interactions")] + [:> icon* {:icon-id i/arrow-down + :size "s" + :class (stl/css :icon-dropdown)}]] [:& dropdown {:show @show-dropdown? :on-close hide-dropdown} [:ul {:class (stl/css :dropdown)} @@ -267,7 +279,7 @@ [:span {:class (stl/css :label)} (tr "viewer.header.dont-show-interactions")] (when (= interactions-mode :hide) - [:span {:class (stl/css :icon)} deprecated-icon/tick])] + [:> icon* {:icon-id i/tick :size "s" :class (stl/css :icon)}])] [:li {:class (stl/css-case :dropdown-element true :selected (= interactions-mode :show)) @@ -275,7 +287,7 @@ :data-mode "show"} [:span {:class (stl/css :label)} (tr "viewer.header.show-interactions")] (when (= interactions-mode :show) - [:span {:class (stl/css :icon)} deprecated-icon/tick])] + [:> icon* {:icon-id i/tick :size "s" :class (stl/css :icon)}])] @@ -286,7 +298,7 @@ [:span {:class (stl/css :label)} (tr "viewer.header.show-interactions-on-click")] (when (= interactions-mode :show-on-click) - [:span {:class (stl/css :icon)} deprecated-icon/tick])]]]])) + [:> icon* {:icon-id i/tick :size "s" :class (stl/css :icon)}])]]]])) (defn animate-go-to-frame [animation current-viewport orig-viewport current-size orig-size wrapper-size] diff --git a/frontend/src/app/main/ui/viewer/interactions.scss b/frontend/src/app/main/ui/viewer/interactions.scss index b17ac08b84..669e02940f 100644 --- a/frontend/src/app/main/ui/viewer/interactions.scss +++ b/frontend/src/app/main/ui/viewer/interactions.scss @@ -4,94 +4,75 @@ // // Copyright (c) KALEIDOS SUBSIDIARY SL +// Only for the shared menu placeholders, which move to the DS with the +// menus and dropdowns. @use "refactor/common-refactor.scss" as deprecated; +@use "ds/_borders.scss" as *; +@use "ds/_sizes.scss" as *; +@use "ds/_utils.scss" as *; +@use "ds/typography.scss" as *; + +.view-options-wrapper { + position: relative; +} .view-options { - @include deprecated.body-small-typography; + @include use-typography("body-small"); display: flex; align-items: center; - position: relative; - gap: deprecated.$s-4; - height: deprecated.$s-32; - border-radius: deprecated.$br-8; - background-color: var(--input-background-color); - padding: deprecated.$s-8; + border: none; + gap: var(--sp-xs); + block-size: $sz-32; + border-radius: $br-8; + background-color: var(--color-background-tertiary); + padding: var(--sp-s); cursor: pointer; } .dropdown-title { - @include deprecated.body-small-typography; + @include use-typography("body-small"); flex-grow: 1; - color: var(--input-foreground-color-active); + color: var(--color-foreground-primary); } .label { flex-grow: 1; - color: var(--input-foreground-color); + color: var(--color-foreground-secondary); } .dropdown { @extend %menu-dropdown; - right: deprecated.$s-2; - top: calc(deprecated.$s-2 + deprecated.$s-48); - width: deprecated.$s-272; - padding: deprecated.$s-6; - max-height: calc(100vh - 3 * (deprecated.$s-2 + deprecated.$s-48)); + inset-inline-end: px2rem(2); + inset-block-start: px2rem(50); + inline-size: px2rem(272); + padding: px2rem(6); + max-block-size: calc(100vh - #{px2rem(150)}); overflow: auto; } .dropdown-element { @extend %dropdown-element-base; - min-height: deprecated.$s-32; - - .icon { - @include deprecated.flex-center; - - height: 100%; - width: deprecated.$s-16; - - svg { - @extend %button-icon-small; - - stroke: var(--icon-foreground); - } - } + min-block-size: $sz-32; &:hover .label { - color: var(--input-foreground-color-active); + color: var(--color-foreground-primary); } } .dropdown-element.selected { .label { - color: var(--input-foreground-color-active); - } - - .icon svg { - stroke: var(--input-foreground-color); + color: var(--color-foreground-primary); } } .icon, .icon-dropdown { - @include deprecated.flex-center; - - height: 100%; - width: deprecated.$s-16; - - svg { - @extend %button-icon-small; - - stroke: var(--icon-foreground); - } -} - -.icon-dropdown svg { - transform: rotate(90deg); + flex-shrink: 0; + color: var(--color-foreground-secondary); } // breakpoint 1013px