mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-09-21 12:19:03 +03:00
Merge pull request #1476 from NoRedInk/tooltip-prevent-default
Prevent default/stop propagation on Tooltip.disclosure click
This commit is contained in:
commit
a3527cf591
@ -18,6 +18,7 @@ import Debug.Control.View as ControlView
|
||||
import EllieLink
|
||||
import Example exposing (Example)
|
||||
import Html.Styled.Attributes exposing (css, href, id)
|
||||
import Html.Styled.Events as Events
|
||||
import KeyboardSupport exposing (Key(..))
|
||||
import Markdown
|
||||
import Nri.Ui.ClickableSvg.V2 as ClickableSvg
|
||||
@ -93,6 +94,7 @@ example =
|
||||
type alias State =
|
||||
{ openTooltip : Maybe TooltipId
|
||||
, staticExampleSettings : Control (List ( String, Tooltip.Attribute Never ))
|
||||
, disclosureModel : { parentClicks : Int }
|
||||
, pageSettings : Control PageSettings
|
||||
}
|
||||
|
||||
@ -101,6 +103,7 @@ init : State
|
||||
init =
|
||||
{ openTooltip = Nothing
|
||||
, staticExampleSettings = initStaticExampleSettings
|
||||
, disclosureModel = { parentClicks = 0 }
|
||||
, pageSettings =
|
||||
Control.record PageSettings
|
||||
|> Control.field "backgroundColor"
|
||||
@ -129,6 +132,11 @@ type Msg
|
||||
| SetControl (Control (List ( String, Tooltip.Attribute Never )))
|
||||
| UpdatePageSettings (Control PageSettings)
|
||||
| Log String
|
||||
| DisclosureMsg DisclosureMsg
|
||||
|
||||
|
||||
type DisclosureMsg
|
||||
= ParentClick
|
||||
|
||||
|
||||
update : Msg -> State -> ( State, Cmd Msg )
|
||||
@ -150,6 +158,9 @@ update msg model =
|
||||
Log message ->
|
||||
( Debug.log "Tooltip Log:" |> always model, Cmd.none )
|
||||
|
||||
DisclosureMsg ParentClick ->
|
||||
( { model | disclosureModel = { parentClicks = model.disclosureModel.parentClicks + 1 } }, Cmd.none )
|
||||
|
||||
|
||||
view : EllieLink.Config -> State -> List (Html Msg)
|
||||
view ellieLinkConfig model =
|
||||
@ -238,7 +249,7 @@ Sometimes a tooltip trigger doesn't have any functionality itself outside of rev
|
||||
|
||||
This behavior is analogous to disclosure behavior, except that it's presented different visually. (For more information, please read [Sarah Higley's "Tooltips in the time of WCAG 2.1" post](https://sarahmhigley.com/writing/tooltips-in-wcag-21).)
|
||||
"""
|
||||
, example = viewDisclosureToolip model.openTooltip
|
||||
, example = viewDisclosureToolip model.openTooltip model.disclosureModel
|
||||
, tooltipId = Disclosure
|
||||
}
|
||||
, { name = "Tooltip.viewToggleTip"
|
||||
@ -304,8 +315,8 @@ viewAuxillaryDescriptionToolip openTooltip =
|
||||
]
|
||||
|
||||
|
||||
viewDisclosureToolip : Maybe TooltipId -> Html Msg
|
||||
viewDisclosureToolip openTooltip =
|
||||
viewDisclosureToolip : Maybe TooltipId -> { parentClicks : Int } -> Html Msg
|
||||
viewDisclosureToolip openTooltip { parentClicks } =
|
||||
let
|
||||
triggerId =
|
||||
"tooltip__disclosure-trigger"
|
||||
@ -313,7 +324,12 @@ viewDisclosureToolip openTooltip =
|
||||
lastId =
|
||||
"tooltip__disclosure-what-is-mastery"
|
||||
in
|
||||
Tooltip.view
|
||||
Html.button
|
||||
[ css [ Css.padding (Css.px 40) ]
|
||||
, Events.onClick (DisclosureMsg ParentClick)
|
||||
, id "parent-button"
|
||||
]
|
||||
[ Tooltip.view
|
||||
{ id = "tooltip__disclosure"
|
||||
, trigger =
|
||||
\eventHandlers ->
|
||||
@ -337,6 +353,8 @@ viewDisclosureToolip openTooltip =
|
||||
, Tooltip.smallPadding
|
||||
, Tooltip.alignEndForMobile (Css.px 148)
|
||||
]
|
||||
, Html.div [ id "parent-button-clicks" ] [ Html.text ("Parent Clicks: " ++ String.fromInt parentClicks) ]
|
||||
]
|
||||
|
||||
|
||||
viewToggleTip : Maybe TooltipId -> Html Msg
|
||||
|
@ -170,10 +170,59 @@ describe("UI tests", function () {
|
||||
handleAxeResults(name, results);
|
||||
};
|
||||
|
||||
const tooltipProcessing = async (name, location) => {
|
||||
await defaultProcessing(name, location);
|
||||
await page.waitForSelector("#parent-button-clicks");
|
||||
|
||||
const buttonClick = async () => {
|
||||
const button = await page.$("#parent-button");
|
||||
await page.evaluate((el) => el.click(), button);
|
||||
await page.waitForTimeout(100);
|
||||
};
|
||||
|
||||
const getCounterText = async () => {
|
||||
const counter = await page.$("#parent-button-clicks");
|
||||
const text = await page.evaluate((el) => el.innerText, counter);
|
||||
return text;
|
||||
};
|
||||
|
||||
const tooltipTriggerClick = async () => {
|
||||
const button = await page.$("#tooltip__disclosure-trigger");
|
||||
await page.evaluate((el) => el.click(), button);
|
||||
await page.waitForTimeout(100);
|
||||
};
|
||||
|
||||
const isTooltipVisible = async () => {
|
||||
let res = await page.evaluate(() => {
|
||||
return (
|
||||
getComputedStyle(
|
||||
document.getElementById("tooltip__disclosure").parentElement
|
||||
).getPropertyValue("display") != "none"
|
||||
);
|
||||
});
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
assert.equal(await getCounterText(), "Parent Clicks: 0");
|
||||
assert.equal(await isTooltipVisible(), false);
|
||||
await tooltipTriggerClick();
|
||||
assert.equal(await isTooltipVisible(), true);
|
||||
await tooltipTriggerClick();
|
||||
assert.equal(await isTooltipVisible(), false);
|
||||
assert.equal(await getCounterText(), "Parent Clicks: 0");
|
||||
await buttonClick();
|
||||
assert.equal(await getCounterText(), "Parent Clicks: 1");
|
||||
await buttonClick();
|
||||
assert.equal(await getCounterText(), "Parent Clicks: 2");
|
||||
};
|
||||
|
||||
const skippedRules = {
|
||||
// Loading's color contrast check seems to change behavior depending on whether Percy snapshots are taken or not
|
||||
Loading: ["color-contrast"],
|
||||
RadioButton: ["duplicate-id"],
|
||||
// We need nested-interactive to test the tooltip behavior
|
||||
Tooltip: ["nested-interactive"],
|
||||
};
|
||||
|
||||
const specialProcessing = {
|
||||
@ -184,6 +233,7 @@ describe("UI tests", function () {
|
||||
UiIcon: iconProcessing,
|
||||
Logo: iconProcessing,
|
||||
Pennant: iconProcessing,
|
||||
Tooltip: tooltipProcessing,
|
||||
};
|
||||
|
||||
it("All", async function () {
|
||||
|
@ -33,6 +33,7 @@ module Nri.Ui.Tooltip.V3 exposing
|
||||
- adds `paragraph` and `markdown` support
|
||||
- add partially-transparent white border around tooltips
|
||||
- Use Nri.Ui.WhenFocusLeaves.V2
|
||||
- prevent default and stop propagation on click for disclosure tooltips
|
||||
|
||||
Changes from V2:
|
||||
|
||||
@ -87,6 +88,7 @@ import Content
|
||||
import Css exposing (Color, Px, Style)
|
||||
import Css.Global as Global
|
||||
import Css.Media
|
||||
import EventExtras as Events
|
||||
import Html.Styled as Root
|
||||
import Html.Styled.Attributes as Attributes
|
||||
import Html.Styled.Events as Events
|
||||
@ -940,7 +942,7 @@ viewTooltip_ { trigger, id } tooltip =
|
||||
, tabForwardAction = msg False
|
||||
}
|
||||
]
|
||||
, [ Events.onClick (msg (not tooltip.isOpen))
|
||||
, [ Events.onClickPreventDefaultAndStopPropagation (msg (not tooltip.isOpen))
|
||||
, Key.onKeyDown [ Key.escape (msg False) ]
|
||||
]
|
||||
)
|
||||
|
@ -1,8 +1,10 @@
|
||||
module Spec.Nri.Ui.Tooltip exposing (spec)
|
||||
|
||||
import Accessibility.Aria as Aria
|
||||
import Html.Attributes as Attributes
|
||||
import Expect
|
||||
import Html.Attributes
|
||||
import Html.Styled as HtmlStyled
|
||||
import Nri.Ui.ClickableText.V3 as ClickableText
|
||||
import Nri.Ui.Tooltip.V3 as Tooltip
|
||||
import ProgramTest exposing (ProgramTest, ensureViewHas, ensureViewHasNot)
|
||||
import Spec.Helpers exposing (nriDescription)
|
||||
@ -82,6 +84,47 @@ spec =
|
||||
]
|
||||
|> ProgramTest.ensureViewHasNot (id tooltipId :: tooltipContentSelector tooltipContent)
|
||||
|> ProgramTest.done
|
||||
, test "Prevents default on disclosures" <|
|
||||
\() ->
|
||||
let
|
||||
tooltipContent =
|
||||
"This will be the primary label"
|
||||
|
||||
triggerContent =
|
||||
"label-less icon"
|
||||
|
||||
tooltipId =
|
||||
"primary-label"
|
||||
|
||||
triggerId =
|
||||
"trigger"
|
||||
|
||||
view model =
|
||||
Tooltip.view
|
||||
{ trigger =
|
||||
\attributes ->
|
||||
ClickableText.button triggerContent
|
||||
[ ClickableText.custom attributes
|
||||
, ClickableText.id triggerId
|
||||
]
|
||||
, id = tooltipId
|
||||
}
|
||||
[ Tooltip.open model.isOpen
|
||||
, Tooltip.plaintext tooltipContent
|
||||
, Tooltip.primaryLabel
|
||||
, Tooltip.onToggle (\_ -> ())
|
||||
, Tooltip.disclosure
|
||||
{ triggerId = triggerId
|
||||
, lastId = Nothing
|
||||
}
|
||||
]
|
||||
|> HtmlStyled.toUnstyled
|
||||
in
|
||||
view { isOpen = False }
|
||||
|> Query.fromHtml
|
||||
|> Query.find [ Selector.id triggerId ]
|
||||
|> Event.simulate Event.click
|
||||
|> Expect.all [ Event.expectStopPropagation, Event.expectPreventDefault ]
|
||||
]
|
||||
|
||||
|
||||
@ -102,7 +145,7 @@ program view attributes =
|
||||
|
||||
tooltipContentSelector : String -> List Selector.Selector
|
||||
tooltipContentSelector tooltipContent =
|
||||
[ Selector.attribute (Attributes.attribute "data-tooltip-visible" "true")
|
||||
[ Selector.attribute (Html.Attributes.attribute "data-tooltip-visible" "true")
|
||||
, Selector.containing [ text tooltipContent ]
|
||||
]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user