From 296fce96cb0d73ecc9505ed314886e5ceabc2abb Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 14:46:03 -0700 Subject: [PATCH 01/32] cp src/Nri/Ui/Tooltip/V2.elm src/Nri/Ui/Tooltip/V3.elm --- src/Nri/Ui/Tooltip/V3.elm | 981 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 981 insertions(+) create mode 100644 src/Nri/Ui/Tooltip/V3.elm diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm new file mode 100644 index 00000000..1444baed --- /dev/null +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -0,0 +1,981 @@ +module Nri.Ui.Tooltip.V2 exposing + ( view, toggleTip + , Attribute + , plaintext, html + , withoutTail + , onTop, onBottom, onLeft, onRight + , alignStart, alignMiddle, alignEnd + , exactWidth, fitToContent + , smallPadding, normalPadding, customPadding + , onClick, onHover + , open + , css, containerCss + , custom, customTriggerAttributes + , nriDescription, testId + , primaryLabel, auxillaryDescription + ) + +{-| Known issues: + + - tooltips with focusable content (e.g., a link) will not handle focus correctly for + keyboard-only users when using the onHover attribute + +Post-release patches: + + - fix overlay for onClick toolTip having a border + - mark customTriggerAttributes as deprecated + - add containerCss + - adds `nriDescription` and `testId` + - fix + - use `Shadows` + +Changes from V1: + + - {Position, withPosition} -> {onTop, onBottom, onLeft, onRight} + - withTooltipStyleOverrides -> css + - {Width, withWidth} -> {exactWidth, fitToContent} + - {Padding, withPadding} -> {smallPadding, normalPadding} + - adds customPadding + - adds custom for custom attributes + - adds plaintext, html helpers for setting the content + - pass a list of attributes rather than requiring a pipeline to set up the tooltip + - move Trigger into the attributes + - change primaryLabel and auxillaryDescription to attributes, adding view + - move the onTrigger event to the attributes + - extraButtonAttrs becomes attribute `customTriggerAttributes` + - isOpen field becomes the `open` attribute + - fold toggleTip and view into each other, so there's less to maintain + - adds withoutTail + +These tooltips follow the accessibility recommendations from: + +Example usage: + + Tooltip.view + { trigger = + \attrs -> + ClickableText.button "Click me to open the tooltip" + [ ClickableText.custom attrs ] + , id = "my-tooltip" + } + [ Tooltip.plaintext "Gradebook" + , Tooltip.primaryLabel + , Tooltip.onClick MyOnTriggerMsg + , Tooltip.open True + ] + +@docs view, toggleTip +@docs Attribute +@docs plaintext, html +@docs withoutTail +@docs onTop, onBottom, onLeft, onRight +@docs alignStart, alignMiddle, alignEnd +@docs exactWidth, fitToContent +@docs smallPadding, normalPadding, customPadding +@docs onClick, onHover +@docs open +@docs css, containerCss +@docs custom, customTriggerAttributes +@docs nriDescription, testId +@docs primaryLabel, auxillaryDescription + +-} + +import Accessibility.Styled as Html exposing (Attribute, Html, text) +import Accessibility.Styled.Aria as Aria +import Accessibility.Styled.Key as Key +import Accessibility.Styled.Role as Role +import Css exposing (Color, Px, Style) +import Css.Global as Global +import EventExtras +import Html.Styled as Root +import Html.Styled.Attributes as Attributes +import Html.Styled.Events as Events +import Json.Encode as Encode +import Nri.Ui +import Nri.Ui.ClickableSvg.V2 as ClickableSvg +import Nri.Ui.Colors.V1 as Colors +import Nri.Ui.Fonts.V1 as Fonts +import Nri.Ui.Html.Attributes.V2 as ExtraAttributes +import Nri.Ui.Shadows.V1 as Shadows +import Nri.Ui.UiIcon.V1 as UiIcon +import String.Extra + + +{-| -} +type Attribute msg + = Attribute (Tooltip msg -> Tooltip msg) + + +type alias Tooltip msg = + { direction : Direction + , alignment : Alignment + , tail : Tail + , content : List (Html msg) + , attributes : List (Html.Attribute Never) + , containerStyles : List Style + , tooltipStyleOverrides : List Style + , width : Width + , padding : Padding + , trigger : Maybe (Trigger msg) + , triggerAttributes : List (Html.Attribute msg) + , purpose : Purpose + , isOpen : Bool + } + + +buildAttributes : List (Attribute msg) -> Tooltip msg +buildAttributes = + let + defaultTooltip : Tooltip msg + defaultTooltip = + { direction = OnTop + , alignment = Middle + , tail = WithTail + , content = [] + , attributes = [] + , containerStyles = + [ Css.boxSizing Css.borderBox + , Css.display Css.inlineBlock + , Css.textAlign Css.left + , Css.position Css.relative + ] + , tooltipStyleOverrides = [] + , width = Exactly 320 + , padding = NormalPadding + , trigger = Nothing + , triggerAttributes = [] + , purpose = PrimaryLabel + , isOpen = False + } + in + List.foldl (\(Attribute applyAttr) acc -> applyAttr acc) defaultTooltip + + +{-| -} +plaintext : String -> Attribute msg +plaintext content = + Attribute (\config -> { config | content = [ text content ] }) + + +{-| -} +html : List (Html msg) -> Attribute msg +html content = + Attribute (\config -> { config | content = content }) + + +type Tail + = WithTail + | WithoutTail + + +{-| Where should the tail be positioned relative to the tooltip? +-} +type Alignment + = Start Px + | Middle + | End Px + + +{-| Makes it so that the tooltip does not have a tail! +-} +withoutTail : Attribute msg +withoutTail = + Attribute (\config -> { config | tail = WithoutTail }) + + +withAligment : Alignment -> Attribute msg +withAligment alignment = + Attribute (\config -> { config | alignment = alignment }) + + +{-| Put the tail at the "start" of the tooltip. +For onTop & onBottom tooltips, this means "left". +For onLeft & onRight tooltip, this means "top". + + __________ + |_ ______| + \/ + +-} +alignStart : Px -> Attribute msg +alignStart position = + withAligment (Start position) + + +{-| Put the tail at the "middle" of the tooltip. This is the default behavior. + + __________ + |___ ____| + \/ + +-} +alignMiddle : Attribute msg +alignMiddle = + withAligment Middle + + +{-| Put the tail at the "end" of the tooltip. +For onTop & onBottom tooltips, this means "right". +For onLeft & onRight tooltip, this means "bottom". + + __________ + |______ _| + \/ + +-} +alignEnd : Px -> Attribute msg +alignEnd position = + withAligment (End position) + + +{-| Where should this tooltip be positioned relative to the trigger? +-} +type Direction + = OnTop + | OnBottom + | OnLeft + | OnRight + + +withPosition : Direction -> Attribute msg +withPosition direction = + Attribute (\config -> { config | direction = direction }) + + +{-| + + __________ + | | + |___ ____| + \/ + +-} +onTop : Attribute msg +onTop = + withPosition OnTop + + +{-| + + __________ + | | + < | + |_________| + +-} +onRight : Attribute msg +onRight = + withPosition OnRight + + +{-| + + ___/\_____ + | | + |_________| + +-} +onBottom : Attribute msg +onBottom = + withPosition OnBottom + + +{-| + + __________ + | | + | > + |_________| + +-} +onLeft : Attribute msg +onLeft = + withPosition OnLeft + + +{-| Set some custom styles on the tooltip. These will be treated as overrides, +so be careful! +-} +css : List Style -> Attribute msg +css tooltipStyleOverrides = + Attribute (\config -> { config | tooltipStyleOverrides = tooltipStyleOverrides }) + + +{-| Use this helper to add custom attributes. + +Do NOT use this helper to add css styles, as they may not be applied the way +you want/expect if underlying styles change. +Instead, please use the `css` helper. + +-} +custom : List (Html.Attribute Never) -> Attribute msg +custom attributes = + Attribute (\config -> { config | attributes = config.attributes ++ attributes }) + + +{-| -} +nriDescription : String -> Attribute msg +nriDescription description = + custom [ ExtraAttributes.nriDescription description ] + + +{-| -} +testId : String -> Attribute msg +testId id_ = + custom [ ExtraAttributes.testId id_ ] + + +{-| DEPRECATED -- a future release will remove this helper. +-} +customTriggerAttributes : List (Html.Attribute msg) -> Attribute msg +customTriggerAttributes attributes = + Attribute (\config -> { config | triggerAttributes = config.triggerAttributes ++ attributes }) + + +{-| -} +containerCss : List Style -> Attribute msg +containerCss styles = + Attribute (\config -> { config | containerStyles = config.containerStyles ++ styles }) + + +{-| Should the tooltip be exactly some measurement or fit to the width of the +content? +-} +type Width + = Exactly Int + | FitToContent + + +withWidth : Width -> Attribute msg +withWidth width = + Attribute (\config -> { config | width = width }) + + +{-| Define a size in `px` for the tooltips's total width. The default is 320px. +-} +exactWidth : Int -> Attribute msg +exactWidth width = + withWidth (Exactly width) + + +{-| Tooltip width fits its content. +-} +fitToContent : Attribute msg +fitToContent = + withWidth FitToContent + + +{-| How much padding should be around the content inside the tooltip? +-} +type Padding + = SmallPadding + | NormalPadding + | CustomPadding Float + + +paddingToStyle : Padding -> Style +paddingToStyle padding = + case padding of + SmallPadding -> + Css.padding2 (Css.px 10) (Css.px 13) + + NormalPadding -> + Css.padding (Css.px 20) + + CustomPadding padding_ -> + Css.padding (Css.px padding_) + + +withPadding : Padding -> Attribute msg +withPadding padding = + Attribute (\config -> { config | padding = padding }) + + +{-| -} +smallPadding : Attribute msg +smallPadding = + withPadding SmallPadding + + +{-| This the default spacing. +-} +normalPadding : Attribute msg +normalPadding = + withPadding NormalPadding + + +{-| Pass in the desired spacing around the edge of the tooltip (pixels). +-} +customPadding : Float -> Attribute msg +customPadding value = + withPadding (CustomPadding value) + + +type Trigger msg + = OnHover (Bool -> msg) + | OnClick (Bool -> msg) + + +{-| The tooltip opens when hovering over the trigger element, and closes when the hover stops. +-} +onHover : (Bool -> msg) -> Attribute msg +onHover msg = + Attribute (\config -> { config | trigger = Just (OnHover msg) }) + + +{-| The tooltip opens when clicking the root element, and closes when anything but the tooltip is clicked again. +-} +onClick : (Bool -> msg) -> Attribute msg +onClick msg = + Attribute (\config -> { config | trigger = Just (OnClick msg) }) + + +type Purpose + = PrimaryLabel + | AuxillaryDescription + + +{-| Used when the content of the tooltip is the "primary label" for its content, for example, +when the trigger content is an icon. The tooltip content will supercede the content of the trigger +HTML for screen readers. + +This is the default. + +-} +primaryLabel : Attribute msg +primaryLabel = + Attribute (\config -> { config | purpose = PrimaryLabel }) + + +{-| Used when the content of the tooltip provides an "auxillary description" for its content. +-} +auxillaryDescription : Attribute msg +auxillaryDescription = + Attribute (\config -> { config | purpose = AuxillaryDescription }) + + +{-| -} +open : Bool -> Attribute msg +open isOpen = + Attribute (\config -> { config | isOpen = isOpen }) + + +{-| Here's what the fields in the configuration record do: + + - `trigger`: What element do you interact with to open the tooltip? + - `id`: A unique identifier used to associate the trigger with its content + +-} +view : + { trigger : List (Html.Attribute msg) -> Html msg + , id : String -- Accessibility: Used to match tooltip to trigger + } + -> List (Attribute msg) + -> Html msg +view config attributes = + viewTooltip_ config (buildAttributes attributes) + + +{-| Supplementary information triggered by a "?" icon. +-} +toggleTip : { label : String } -> List (Attribute msg) -> Html msg +toggleTip { label } attributes_ = + let + id = + String.Extra.dasherize label + in + view + { trigger = + \events -> + ClickableSvg.button label + UiIcon.help + [ ClickableSvg.exactWidth 20 + , ClickableSvg.exactHeight 20 + , ClickableSvg.custom events + , ClickableSvg.css + [ -- Take up enough room within the document flow + Css.margin (Css.px 5) + ] + ] + , id = id + } + (custom + [ Attributes.class "Nri-Ui-Tooltip-V2-ToggleTip" + , Attributes.id id + ] + :: attributes_ + ) + + + +-- INTERNALS + + +viewTooltip_ : + { trigger : List (Html.Attribute msg) -> Html msg + , id : String -- Accessibility: Used to match tooltip to trigger + } + -> Tooltip msg + -> Html msg +viewTooltip_ { trigger, id } tooltip = + let + ( containerEvents, buttonEvents ) = + case tooltip.trigger of + Just (OnClick msg) -> + ( [] + , [ EventExtras.onClickStopPropagation + (msg (not tooltip.isOpen)) + ] + ) + + Just (OnHover msg) -> + ( [ Events.onMouseEnter (msg True) + , Events.onMouseLeave (msg False) + ] + , [ Events.onFocus (msg True) + + -- TODO: this blur event means that we cannot focus links + -- that are within the tooltip without a mouse + , Events.onBlur (msg False) + , Events.onClick (msg True) + ] + ) + + Nothing -> + ( [], [] ) + in + Nri.Ui.styled Root.div + "Nri-Ui-Tooltip-V2" + tooltip.containerStyles + containerEvents + [ Html.div + [ Attributes.css + [ -- using display flex not so that the wrapping div fits its + -- contents exactly. otherwise, it will be at least of the + -- size of a line of text, adding some extra vertical space + -- when the trigger is short (making it look like vertical + -- alignment is broken). if you ever need to change this back + -- to `block` or `inline-block`, consider adjusting the + -- `font-size` to zero to achieve a similar effect. + Css.displayFlex + ] + ] + [ trigger + ((if tooltip.isOpen then + case tooltip.purpose of + PrimaryLabel -> + Aria.labeledBy id + + AuxillaryDescription -> + Aria.describedBy [ id ] + + else + -- when our tooltips are closed, they're not rendered in the + -- DOM. This means that the ID references above would be + -- invalid and jumping to a reference would not work, so we + -- skip labels and descriptions if the tooltip is closed. + Attributes.property "data-closed-tooltip" Encode.null + ) + :: buttonEvents + ++ tooltip.triggerAttributes + ) + , hoverBridge tooltip + ] + , viewOverlay tooltip + + -- Popout is rendered after the overlay, to allow client code to give it + -- priority when clicking by setting its position + , viewTooltip id tooltip + ] + + +{-| This is a "bridge" for the cursor to move from trigger content to tooltip, so the user can click on links, etc. +-} +hoverBridge : Tooltip msg -> Html msg +hoverBridge { isOpen, direction } = + let + bridgeLength = + tailSize + 5 + in + if isOpen then + Nri.Ui.styled Html.div + "tooltip-hover-bridge" + [ Css.boxSizing Css.borderBox + , Css.padding (Css.px tailSize) + , Css.position Css.absolute + , Css.batch <| + case direction of + OnTop -> + [ Css.top (Css.px -bridgeLength) + , Css.left Css.zero + , Css.width (Css.pct 100) + , Css.height (Css.px tailSize) + ] + + OnRight -> + [ Css.right (Css.px -bridgeLength) + , Css.top Css.zero + , Css.width (Css.px tailSize) + , Css.height (Css.pct 100) + ] + + OnBottom -> + [ Css.bottom (Css.px -bridgeLength) + , Css.left Css.zero + , Css.width (Css.pct 100) + , Css.height (Css.px tailSize) + ] + + OnLeft -> + [ Css.left (Css.px -bridgeLength) + , Css.top Css.zero + , Css.width (Css.px tailSize) + , Css.height (Css.pct 100) + ] + ] + [] + [] + + else + text "" + + +viewTooltip : String -> Tooltip msg -> Html msg +viewTooltip tooltipId config = + if config.isOpen then + viewOpenTooltip tooltipId config + + else + text "" + + +viewOpenTooltip : String -> Tooltip msg -> Html msg +viewOpenTooltip tooltipId config = + Html.div + [ Attributes.css + [ Css.position Css.absolute + , positionTooltip config.direction config.alignment + , Css.boxSizing Css.borderBox + ] + ] + [ Html.div + ([ Attributes.css + ([ Css.boxSizing Css.borderBox + , Css.borderRadius (Css.px 8) + , case config.width of + Exactly width -> + Css.width (Css.px (toFloat width)) + + FitToContent -> + Css.whiteSpace Css.noWrap + , paddingToStyle config.padding + , Css.position Css.absolute + , Css.zIndex (Css.int 100) + ] + ++ config.tooltipStyleOverrides + ) + , pointerBox config.tail config.direction config.alignment + + -- We need to keep this animation in tests to make it pass: check out + -- the NoAnimations middleware. So if you change the name here, please + -- change that as well + , Attributes.class "dont-disable-animation" + , Role.toolTip + ] + ++ config.attributes + ++ [ Attributes.id tooltipId ] + ) + config.content + ] + + +tailSize : Float +tailSize = + 8 + + +tooltipColor : Color +tooltipColor = + Colors.navy + + +offCenterOffset : Float +offCenterOffset = + 20 + + +{-| This returns an absolute positioning style attribute for the popout container for a given tail position. +-} +positionTooltip : Direction -> Alignment -> Style +positionTooltip direction alignment = + let + ltrPosition = + case alignment of + Start customOffset -> + Css.left customOffset + + Middle -> + Css.left (Css.pct 50) + + End customOffset -> + Css.right customOffset + + topToBottomPosition = + case alignment of + Start customOffset -> + Css.top customOffset + + Middle -> + Css.top (Css.pct 50) + + End customOffset -> + Css.bottom customOffset + in + Css.batch <| + case direction of + OnTop -> + [ ltrPosition + , Css.top (Css.calc (Css.px (negate tailSize)) Css.minus (Css.px 2)) + ] + + OnBottom -> + [ ltrPosition + , Css.bottom (Css.calc (Css.px (negate tailSize)) Css.minus (Css.px 2)) + ] + + OnLeft -> + [ topToBottomPosition + , Css.left (Css.calc (Css.px (negate tailSize)) Css.minus (Css.px 2)) + ] + + OnRight -> + [ topToBottomPosition + , Css.right (Css.calc (Css.px (negate tailSize)) Css.minus (Css.px 2)) + ] + + +pointerBox : Tail -> Direction -> Alignment -> Html.Attribute msg +pointerBox tail direction alignment = + Attributes.css + [ Css.backgroundColor Colors.navy + , Css.border3 (Css.px 1) Css.solid Colors.navy + , positioning direction alignment + , case tail of + WithTail -> + tailForDirection direction + + WithoutTail -> + Css.batch [] + , Fonts.baseFont + , Css.fontSize (Css.px 16) + , Css.fontWeight (Css.int 600) + , Css.color Colors.white + , Shadows.high + , Global.descendants [ Global.a [ Css.textDecoration Css.underline ] ] + , Global.descendants [ Global.a [ Css.color Colors.white ] ] + ] + + +viewOverlay : Tooltip msg -> Html msg +viewOverlay { isOpen, trigger } = + case ( isOpen, trigger ) of + ( True, Just (OnClick msg) ) -> + -- if we display the click-to-close overlay on hover, you will have to + -- close the overlay by moving the mouse out of the window or clicking. + viewCloseTooltipOverlay (msg False) + + _ -> + text "" + + +viewCloseTooltipOverlay : msg -> Html msg +viewCloseTooltipOverlay msg = + Html.button + [ Attributes.css + [ Css.width (Css.pct 100) + , -- ancestor uses transform property, which interacts with + -- position: fixed, forcing this hack. + -- https://www.w3.org/TR/css-transforms-1/#propdef-transform + Css.height (Css.calc (Css.px 1000) Css.plus (Css.calc (Css.pct 100) Css.plus (Css.px 1000))) + , Css.left Css.zero + , Css.top (Css.px -1000) + , Css.cursor Css.pointer + , Css.position Css.fixed + , Css.zIndex (Css.int 90) -- TODO: From Nri.ZIndex in monolith, bring ZIndex here? + , Css.backgroundColor Css.transparent + , Css.border Css.zero + , Css.outline Css.none + ] + , EventExtras.onClickStopPropagation msg + , Key.tabbable False + ] + [] + + + +-- TAILS + + +positioning : Direction -> Alignment -> Style +positioning direction alignment = + let + topBottomAlignment = + case alignment of + Start _ -> + Css.left (Css.px offCenterOffset) + + Middle -> + Css.left (Css.pct 50) + + End _ -> + Css.right (Css.px offCenterOffset) + + rightLeftAlignment = + case alignment of + Start _ -> + Css.property "top" ("calc(-" ++ String.fromFloat tailSize ++ "px + " ++ String.fromFloat offCenterOffset ++ "px)") + + Middle -> + Css.property "top" ("calc(-" ++ String.fromFloat tailSize ++ "px + 50%)") + + End _ -> + Css.property "bottom" ("calc(-" ++ String.fromFloat tailSize ++ "px + " ++ String.fromFloat offCenterOffset ++ "px)") + in + case direction of + OnTop -> + Css.batch + [ Css.property "transform" "translate(-50%, -100%)" + , getTailPositioning + { xAlignment = topBottomAlignment + , yAlignment = Css.top (Css.pct 100) + } + ] + + OnBottom -> + Css.batch + [ Css.property "transform" "translate(-50%, 0)" + , getTailPositioning + { xAlignment = topBottomAlignment + , yAlignment = Css.bottom (Css.pct 100) + } + ] + + OnRight -> + Css.batch + [ Css.property "transform" "translate(0, -50%)" + , getTailPositioning + { xAlignment = Css.right (Css.pct 100) + , yAlignment = rightLeftAlignment + } + ] + + OnLeft -> + Css.batch + [ Css.property "transform" "translate(-100%, -50%)" + , getTailPositioning + { xAlignment = Css.left (Css.pct 100) + , yAlignment = rightLeftAlignment + } + ] + + +tailForDirection : Direction -> Style +tailForDirection direction = + case direction of + OnTop -> + bottomTail + + OnBottom -> + topTail + + OnRight -> + leftTail + + OnLeft -> + rightTail + + +bottomTail : Style +bottomTail = + Css.batch + [ Css.before + [ Css.borderTopColor tooltipColor + , Css.property "border-width" (String.fromFloat (tailSize + 1) ++ "px") + , Css.marginLeft (Css.px (-tailSize - 1)) + ] + , Css.after + [ Css.borderTopColor tooltipColor + , Css.property "border-width" (String.fromFloat tailSize ++ "px") + , Css.marginLeft (Css.px -tailSize) + ] + ] + + +topTail : Style +topTail = + Css.batch + [ Css.before + [ Css.borderBottomColor tooltipColor + , Css.property "border-width" (String.fromFloat (tailSize + 1) ++ "px") + , Css.marginLeft (Css.px (-tailSize - 1)) + ] + , Css.after + [ Css.borderBottomColor tooltipColor + , Css.property "border-width" (String.fromFloat tailSize ++ "px") + , Css.marginLeft (Css.px -tailSize) + ] + ] + + +rightTail : Style +rightTail = + Css.batch + [ Css.before + [ Css.borderLeftColor tooltipColor + , Css.property "border-width" (String.fromFloat (tailSize + 1) ++ "px") + ] + , Css.after + [ Css.borderLeftColor tooltipColor + , Css.property "border-width" (String.fromFloat tailSize ++ "px") + , Css.marginTop (Css.px 1) + , Css.marginRight (Css.px 2) + ] + ] + + +leftTail : Style +leftTail = + Css.batch + [ Css.before + [ Css.borderRightColor tooltipColor + , Css.property "border-width" (String.fromFloat (tailSize + 1) ++ "px") + ] + , Css.after + [ Css.borderRightColor tooltipColor + , Css.property "border-width" (String.fromFloat tailSize ++ "px") + , Css.marginTop (Css.px 1) + , Css.marginLeft (Css.px 2) + ] + ] + + +getTailPositioning : { xAlignment : Style, yAlignment : Style } -> Style +getTailPositioning config = + Css.batch + [ Css.before (positionTail config) + , Css.after (positionTail config) + ] + + +positionTail : { xAlignment : Style, yAlignment : Style } -> List Style +positionTail { xAlignment, yAlignment } = + [ xAlignment + , yAlignment + , Css.property "border" "solid transparent" + , Css.property "content" "\" \"" + , Css.height Css.zero + , Css.width Css.zero + , Css.position Css.absolute + , Css.pointerEvents Css.none + ] From 447687c9130cdc11f1ab3d0f83127d540fc92674 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 15:42:25 -0700 Subject: [PATCH 02/32] Switch on to V3 --- deprecated-modules.csv | 3 +- elm.json | 1 + forbidden-imports.toml | 5 ++- src/Nri/Ui/SegmentedControl/V14.elm | 8 +++-- src/Nri/Ui/Tabs/V7.elm | 8 +++-- src/Nri/Ui/Tooltip/V3.elm | 34 ++------------------ src/TabsInternal/V2.elm | 2 +- styleguide-app/Examples/ClickableSvg.elm | 2 +- styleguide-app/Examples/SegmentedControl.elm | 2 +- styleguide-app/Examples/Tabs.elm | 2 +- styleguide-app/Examples/Tooltip.elm | 14 ++++---- tests/elm-verify-examples.json | 1 + 12 files changed, 33 insertions(+), 49 deletions(-) diff --git a/deprecated-modules.csv b/deprecated-modules.csv index f2553508..46a841c4 100644 --- a/deprecated-modules.csv +++ b/deprecated-modules.csv @@ -10,4 +10,5 @@ Nri.Ui.SideNav.V2,upgrade to V3 Nri.Ui.Switch.V1,upgrade to V2 Nri.Ui.Table.V4,upgrade to V5 Nri.Ui.Tabs.V6,upgrade to V7 -Nri.Ui.Tooltip.V1,upgrade to V2 +Nri.Ui.Tooltip.V1,upgrade to V3 +Nri.Ui.Tooltip.V2,upgrade to V3 diff --git a/elm.json b/elm.json index b8ac22d9..e3554bf3 100644 --- a/elm.json +++ b/elm.json @@ -72,6 +72,7 @@ "Nri.Ui.TextInput.V7", "Nri.Ui.Tooltip.V1", "Nri.Ui.Tooltip.V2", + "Nri.Ui.Tooltip.V3", "Nri.Ui.UiIcon.V1" ], "elm-version": "0.19.0 <= v < 0.20.0", diff --git a/forbidden-imports.toml b/forbidden-imports.toml index 14c840fc..18034712 100644 --- a/forbidden-imports.toml +++ b/forbidden-imports.toml @@ -149,5 +149,8 @@ hint = 'upgrade to V6' hint = 'upgrade to V7' [forbidden."Nri.Ui.Tooltip.V1"] -hint = 'upgrade to V2' +hint = 'upgrade to V3' usages = ['styleguide/../src/Nri/Ui/Menu/V1.elm'] + +[forbidden."Nri.Ui.Tooltip.V2"] +hint = 'upgrade to V3' diff --git a/src/Nri/Ui/SegmentedControl/V14.elm b/src/Nri/Ui/SegmentedControl/V14.elm index d8b47457..2397addd 100644 --- a/src/Nri/Ui/SegmentedControl/V14.elm +++ b/src/Nri/Ui/SegmentedControl/V14.elm @@ -4,7 +4,11 @@ module Nri.Ui.SegmentedControl.V14 exposing , Positioning(..), Width(..) ) -{-| Changes from V13: +{-| Patch changes: + + - use Tooltip.V3 instead of Tooltip.V2 + +Changes from V13: - Adds tooltip support to `viewRadioGroup` @@ -26,7 +30,7 @@ import Nri.Ui.Colors.Extra exposing (withAlpha) import Nri.Ui.Colors.V1 as Colors import Nri.Ui.Fonts.V1 as Fonts import Nri.Ui.Svg.V1 as Svg exposing (Svg) -import Nri.Ui.Tooltip.V2 as Tooltip +import Nri.Ui.Tooltip.V3 as Tooltip import Nri.Ui.Util exposing (dashify) import TabsInternal.V2 as TabsInternal diff --git a/src/Nri/Ui/Tabs/V7.elm b/src/Nri/Ui/Tabs/V7.elm index dbe946f4..20c8a665 100644 --- a/src/Nri/Ui/Tabs/V7.elm +++ b/src/Nri/Ui/Tabs/V7.elm @@ -7,7 +7,11 @@ module Nri.Ui.Tabs.V7 exposing , spaHref ) -{-| Changes from V6: +{-| Patch changes: + + - use Tooltip.V3 instead of Tooltip.V2 + +Changes from V6: - Changes Tab construction to follow attributes-based approach - Adds tooltip support @@ -29,7 +33,7 @@ import Nri.Ui import Nri.Ui.Colors.Extra exposing (withAlpha) import Nri.Ui.Colors.V1 as Colors import Nri.Ui.Fonts.V1 as Fonts -import Nri.Ui.Tooltip.V2 as Tooltip +import Nri.Ui.Tooltip.V3 as Tooltip import TabsInternal.V2 as TabsInternal diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index 1444baed..c17ce0db 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -1,4 +1,4 @@ -module Nri.Ui.Tooltip.V2 exposing +module Nri.Ui.Tooltip.V3 exposing ( view, toggleTip , Attribute , plaintext, html @@ -15,37 +15,7 @@ module Nri.Ui.Tooltip.V2 exposing , primaryLabel, auxillaryDescription ) -{-| Known issues: - - - tooltips with focusable content (e.g., a link) will not handle focus correctly for - keyboard-only users when using the onHover attribute - -Post-release patches: - - - fix overlay for onClick toolTip having a border - - mark customTriggerAttributes as deprecated - - add containerCss - - adds `nriDescription` and `testId` - - fix - - use `Shadows` - -Changes from V1: - - - {Position, withPosition} -> {onTop, onBottom, onLeft, onRight} - - withTooltipStyleOverrides -> css - - {Width, withWidth} -> {exactWidth, fitToContent} - - {Padding, withPadding} -> {smallPadding, normalPadding} - - adds customPadding - - adds custom for custom attributes - - adds plaintext, html helpers for setting the content - - pass a list of attributes rather than requiring a pipeline to set up the tooltip - - move Trigger into the attributes - - change primaryLabel and auxillaryDescription to attributes, adding view - - move the onTrigger event to the attributes - - extraButtonAttrs becomes attribute `customTriggerAttributes` - - isOpen field becomes the `open` attribute - - fold toggleTip and view into each other, so there's less to maintain - - adds withoutTail +{-| Changes from V2: These tooltips follow the accessibility recommendations from: diff --git a/src/TabsInternal/V2.elm b/src/TabsInternal/V2.elm index a156d7de..a7a77d66 100644 --- a/src/TabsInternal/V2.elm +++ b/src/TabsInternal/V2.elm @@ -21,7 +21,7 @@ import Html.Styled.Events as Events import Html.Styled.Keyed as Keyed import Json.Decode import Nri.Ui.Html.Attributes.V2 as AttributesExtra -import Nri.Ui.Tooltip.V2 as Tooltip +import Nri.Ui.Tooltip.V3 as Tooltip import Nri.Ui.Util exposing (dashify) diff --git a/styleguide-app/Examples/ClickableSvg.elm b/styleguide-app/Examples/ClickableSvg.elm index b62de2f9..382e5a91 100644 --- a/styleguide-app/Examples/ClickableSvg.elm +++ b/styleguide-app/Examples/ClickableSvg.elm @@ -20,7 +20,7 @@ import Html.Styled.Attributes as Attributes import Nri.Ui.ClickableSvg.V2 as ClickableSvg import Nri.Ui.Colors.V1 as Colors import Nri.Ui.Svg.V1 exposing (Svg) -import Nri.Ui.Tooltip.V2 as Tooltip +import Nri.Ui.Tooltip.V3 as Tooltip import Nri.Ui.UiIcon.V1 as UiIcon diff --git a/styleguide-app/Examples/SegmentedControl.elm b/styleguide-app/Examples/SegmentedControl.elm index 1727a287..4e714dc4 100644 --- a/styleguide-app/Examples/SegmentedControl.elm +++ b/styleguide-app/Examples/SegmentedControl.elm @@ -26,7 +26,7 @@ import Nri.Ui.Colors.V1 as Colors import Nri.Ui.Fonts.V1 as Fonts import Nri.Ui.SegmentedControl.V14 as SegmentedControl import Nri.Ui.Svg.V1 as Svg exposing (Svg) -import Nri.Ui.Tooltip.V2 as Tooltip +import Nri.Ui.Tooltip.V3 as Tooltip import Nri.Ui.UiIcon.V1 as UiIcon import String exposing (toLower) import Task diff --git a/styleguide-app/Examples/Tabs.elm b/styleguide-app/Examples/Tabs.elm index 8d596c91..d4633233 100644 --- a/styleguide-app/Examples/Tabs.elm +++ b/styleguide-app/Examples/Tabs.elm @@ -22,7 +22,7 @@ import Nri.Ui.Colors.V1 as Colors import Nri.Ui.Svg.V1 as Svg import Nri.Ui.Tabs.V7 as Tabs exposing (Alignment(..), Tab) import Nri.Ui.Text.V6 as Text -import Nri.Ui.Tooltip.V2 as Tooltip +import Nri.Ui.Tooltip.V3 as Tooltip import Nri.Ui.UiIcon.V1 as UiIcon import Routes import Task diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index f0ab5b24..084a1820 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -21,13 +21,18 @@ import Nri.Ui.ClickableSvg.V2 as ClickableSvg import Nri.Ui.ClickableText.V3 as ClickableText import Nri.Ui.Heading.V2 as Heading import Nri.Ui.Text.V6 as Text -import Nri.Ui.Tooltip.V2 as Tooltip +import Nri.Ui.Tooltip.V3 as Tooltip import Nri.Ui.UiIcon.V1 as UiIcon version : Int version = - 2 + 3 + + +moduleName : String +moduleName = + "Tooltip" example : Example State Msg @@ -69,11 +74,6 @@ example = } -moduleName : String -moduleName = - "Tooltip" - - type alias State = { openTooltip : Maybe TooltipType , staticExampleSettings : Control (List ( String, Tooltip.Attribute Never )) diff --git a/tests/elm-verify-examples.json b/tests/elm-verify-examples.json index e4b8bea7..a5bd7147 100644 --- a/tests/elm-verify-examples.json +++ b/tests/elm-verify-examples.json @@ -68,6 +68,7 @@ "Nri.Ui.TextInput.V7", "Nri.Ui.Tooltip.V1", "Nri.Ui.Tooltip.V2", + "Nri.Ui.Tooltip.V3", "Nri.Ui.UiIcon.V1" ] } From 1c4722713e10b293649d37e8ba71d8e1565bca61 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 16:08:30 -0700 Subject: [PATCH 03/32] Begin adding Disclosure, and further clarifying the different patterns available --- src/Nri/Ui/Tooltip/V3.elm | 70 ++++++++++++++++++----------- styleguide-app/Examples/Tooltip.elm | 6 +-- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index c17ce0db..ccb93d65 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -12,12 +12,18 @@ module Nri.Ui.Tooltip.V3 exposing , css, containerCss , custom, customTriggerAttributes , nriDescription, testId - , primaryLabel, auxillaryDescription + , primaryLabel, auxillaryDescription, disclosure ) {-| Changes from V2: -These tooltips follow the accessibility recommendations from: + - Support `disclosure` pattern for rich-content tooltips + - render tooltip content in the DOM when closed (now, they're hidden with display:none) + +These tooltips aim to follow the accessibility recommendations from: + + - + - Example usage: @@ -47,7 +53,7 @@ Example usage: @docs css, containerCss @docs custom, customTriggerAttributes @docs nriDescription, testId -@docs primaryLabel, auxillaryDescription +@docs primaryLabel, auxillaryDescription, disclosure -} @@ -55,6 +61,7 @@ import Accessibility.Styled as Html exposing (Attribute, Html, text) import Accessibility.Styled.Aria as Aria import Accessibility.Styled.Key as Key import Accessibility.Styled.Role as Role +import Accessibility.Styled.Widget as Widget import Css exposing (Color, Px, Style) import Css.Global as Global import EventExtras @@ -404,10 +411,11 @@ onClick msg = type Purpose = PrimaryLabel | AuxillaryDescription + | Disclosure {-| Used when the content of the tooltip is the "primary label" for its content, for example, -when the trigger content is an icon. The tooltip content will supercede the content of the trigger +when the trigger content is a ClickableSvg. The tooltip content will supercede the content of the trigger HTML for screen readers. This is the default. @@ -419,12 +427,28 @@ primaryLabel = {-| Used when the content of the tooltip provides an "auxillary description" for its content. + +An auxillary description is used when the tooltip content provides supplementary information about its trigger content +e.g. when the trigger content is a word in the middle of a body of text that requires additional explanation. + -} auxillaryDescription : Attribute msg auxillaryDescription = Attribute (\config -> { config | purpose = AuxillaryDescription }) +{-| Sometimes a "tooltip" only _looks_ like a tooltip, but is really more about hiding and showing extra information when the user asks for it. + +If clicking the "tooltip trigger" only ever shows you more info (and especially if this info is rich or interactable), use this attribute. + +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). + +-} +disclosure : Attribute msg +disclosure = + Attribute (\config -> { config | purpose = Disclosure }) + + {-| -} open : Bool -> Attribute msg open isOpen = @@ -474,6 +498,7 @@ toggleTip { label } attributes_ = [ Attributes.class "Nri-Ui-Tooltip-V2-ToggleTip" , Attributes.id id ] + :: disclosure :: attributes_ ) @@ -532,22 +557,19 @@ viewTooltip_ { trigger, id } tooltip = ] ] [ trigger - ((if tooltip.isOpen then - case tooltip.purpose of - PrimaryLabel -> - Aria.labeledBy id + ((case tooltip.purpose of + PrimaryLabel -> + [ Aria.labeledBy id ] - AuxillaryDescription -> - Aria.describedBy [ id ] + AuxillaryDescription -> + [ Aria.describedBy [ id ] ] - else - -- when our tooltips are closed, they're not rendered in the - -- DOM. This means that the ID references above would be - -- invalid and jumping to a reference would not work, so we - -- skip labels and descriptions if the tooltip is closed. - Attributes.property "data-closed-tooltip" Encode.null + Disclosure -> + [ Widget.expanded tooltip.isOpen + , Aria.controls id + ] ) - :: buttonEvents + ++ buttonEvents ++ tooltip.triggerAttributes ) , hoverBridge tooltip @@ -613,20 +635,16 @@ hoverBridge { isOpen, direction } = viewTooltip : String -> Tooltip msg -> Html msg viewTooltip tooltipId config = - if config.isOpen then - viewOpenTooltip tooltipId config - - else - text "" - - -viewOpenTooltip : String -> Tooltip msg -> Html msg -viewOpenTooltip tooltipId config = Html.div [ Attributes.css [ Css.position Css.absolute , positionTooltip config.direction config.alignment , Css.boxSizing Css.borderBox + , if config.isOpen then + Css.batch [] + + else + Css.display Css.none ] ] [ Html.div diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index 084a1820..17c58840 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -176,11 +176,7 @@ viewAuxillaryDescriptionToolip openTooltip = viewToggleTip : Maybe TooltipType -> Html Msg viewToggleTip openTooltip = Tooltip.toggleTip { label = "tooltip__learn-more" } - [ Tooltip.html - [ Html.a - [ href "https://inclusive-components.design/tooltips-toggletips" ] - [ Html.text "Learn more" ] - ] + [ Tooltip.plaintext "There's also a convenient `toggleTip` helper, for when you want to add some helpful extra info." , Tooltip.primaryLabel , Tooltip.onHover (ToggleTooltip LearnMore) , Tooltip.open (openTooltip == Just LearnMore) From 3e9a7467a350c5e470f08204c0f57d3e5059bdda Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 16:13:24 -0700 Subject: [PATCH 04/32] Allow users to close tooltips with Space --- src/Nri/Ui/Tooltip/V3.elm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index ccb93d65..4208802c 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -19,6 +19,7 @@ module Nri.Ui.Tooltip.V3 exposing - Support `disclosure` pattern for rich-content tooltips - render tooltip content in the DOM when closed (now, they're hidden with display:none) + - tooltips MUST be closable via keyboard without moving focus. [Understanding Success Criterion 1.4.13: Content on Hover or Focus](https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus.html) These tooltips aim to follow the accessibility recommendations from: @@ -533,7 +534,8 @@ viewTooltip_ { trigger, id } tooltip = -- TODO: this blur event means that we cannot focus links -- that are within the tooltip without a mouse , Events.onBlur (msg False) - , Events.onClick (msg True) + , Events.onClick (msg (not tooltip.isOpen)) + , Key.onKeyDown [ Key.escape (msg False) ] ] ) From 769669bc81735b10b5383bada5e3d972f572545f Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 16:27:57 -0700 Subject: [PATCH 05/32] :skull: remove onClick option that's discouraged by the styleguide --- src/Nri/Ui/Tooltip/V3.elm | 59 ++------------------------------------- 1 file changed, 3 insertions(+), 56 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index 4208802c..f6ef3b4f 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -7,7 +7,7 @@ module Nri.Ui.Tooltip.V3 exposing , alignStart, alignMiddle, alignEnd , exactWidth, fitToContent , smallPadding, normalPadding, customPadding - , onClick, onHover + , onHover , open , css, containerCss , custom, customTriggerAttributes @@ -20,6 +20,7 @@ module Nri.Ui.Tooltip.V3 exposing - Support `disclosure` pattern for rich-content tooltips - render tooltip content in the DOM when closed (now, they're hidden with display:none) - tooltips MUST be closable via keyboard without moving focus. [Understanding Success Criterion 1.4.13: Content on Hover or Focus](https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus.html) + - remove onClick helper These tooltips aim to follow the accessibility recommendations from: @@ -37,7 +38,7 @@ Example usage: } [ Tooltip.plaintext "Gradebook" , Tooltip.primaryLabel - , Tooltip.onClick MyOnTriggerMsg + , Tooltip.onHover MyOnTriggerMsg , Tooltip.open True ] @@ -65,11 +66,9 @@ import Accessibility.Styled.Role as Role import Accessibility.Styled.Widget as Widget import Css exposing (Color, Px, Style) import Css.Global as Global -import EventExtras import Html.Styled as Root import Html.Styled.Attributes as Attributes import Html.Styled.Events as Events -import Json.Encode as Encode import Nri.Ui import Nri.Ui.ClickableSvg.V2 as ClickableSvg import Nri.Ui.Colors.V1 as Colors @@ -392,7 +391,6 @@ customPadding value = type Trigger msg = OnHover (Bool -> msg) - | OnClick (Bool -> msg) {-| The tooltip opens when hovering over the trigger element, and closes when the hover stops. @@ -402,13 +400,6 @@ onHover msg = Attribute (\config -> { config | trigger = Just (OnHover msg) }) -{-| The tooltip opens when clicking the root element, and closes when anything but the tooltip is clicked again. --} -onClick : (Bool -> msg) -> Attribute msg -onClick msg = - Attribute (\config -> { config | trigger = Just (OnClick msg) }) - - type Purpose = PrimaryLabel | AuxillaryDescription @@ -518,13 +509,6 @@ viewTooltip_ { trigger, id } tooltip = let ( containerEvents, buttonEvents ) = case tooltip.trigger of - Just (OnClick msg) -> - ( [] - , [ EventExtras.onClickStopPropagation - (msg (not tooltip.isOpen)) - ] - ) - Just (OnHover msg) -> ( [ Events.onMouseEnter (msg True) , Events.onMouseLeave (msg False) @@ -576,7 +560,6 @@ viewTooltip_ { trigger, id } tooltip = ) , hoverBridge tooltip ] - , viewOverlay tooltip -- Popout is rendered after the overlay, to allow client code to give it -- priority when clicking by setting its position @@ -767,42 +750,6 @@ pointerBox tail direction alignment = ] -viewOverlay : Tooltip msg -> Html msg -viewOverlay { isOpen, trigger } = - case ( isOpen, trigger ) of - ( True, Just (OnClick msg) ) -> - -- if we display the click-to-close overlay on hover, you will have to - -- close the overlay by moving the mouse out of the window or clicking. - viewCloseTooltipOverlay (msg False) - - _ -> - text "" - - -viewCloseTooltipOverlay : msg -> Html msg -viewCloseTooltipOverlay msg = - Html.button - [ Attributes.css - [ Css.width (Css.pct 100) - , -- ancestor uses transform property, which interacts with - -- position: fixed, forcing this hack. - -- https://www.w3.org/TR/css-transforms-1/#propdef-transform - Css.height (Css.calc (Css.px 1000) Css.plus (Css.calc (Css.pct 100) Css.plus (Css.px 1000))) - , Css.left Css.zero - , Css.top (Css.px -1000) - , Css.cursor Css.pointer - , Css.position Css.fixed - , Css.zIndex (Css.int 90) -- TODO: From Nri.ZIndex in monolith, bring ZIndex here? - , Css.backgroundColor Css.transparent - , Css.border Css.zero - , Css.outline Css.none - ] - , EventExtras.onClickStopPropagation msg - , Key.tabbable False - ] - [] - - -- TAILS From e3af01a58ebd2ea49861a1723cec4a2c1230a842 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 16:28:06 -0700 Subject: [PATCH 06/32] Adds keyboard support notes --- styleguide-app/Examples/Tooltip.elm | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index 17c58840..c2b70e8d 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -17,6 +17,7 @@ import Debug.Control.View as ControlView import EllieLink import Example exposing (Example) import Html.Styled.Attributes exposing (css, href) +import KeyboardSupport exposing (Key(..)) import Nri.Ui.ClickableSvg.V2 as ClickableSvg import Nri.Ui.ClickableText.V3 as ClickableText import Nri.Ui.Heading.V2 as Heading @@ -40,7 +41,17 @@ example = { name = moduleName , version = version , categories = [ Messaging ] - , keyboardSupport = [] + , keyboardSupport = + [ { keys = [ Esc ] + , result = "Hitting escape closes all tooltips." + } + , { keys = [ Space ] + , result = "While focusing a tooltip trigger, opens/closes the tooltip. May trigger the underlying action too." + } + , { keys = [ Enter ] + , result = "While focusing a tooltip trigger, opens/closes the tooltip. May trigger the underlying action too." + } + ] , state = init , update = update , subscriptions = \_ -> Sub.none From 5684c32df6e83c265421a2509473ad8671b683c8 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 16:38:14 -0700 Subject: [PATCH 07/32] Remove redundant labeled by --- src/Nri/Ui/Tooltip/V3.elm | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index f6ef3b4f..28188a71 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -21,6 +21,7 @@ module Nri.Ui.Tooltip.V3 exposing - render tooltip content in the DOM when closed (now, they're hidden with display:none) - tooltips MUST be closable via keyboard without moving focus. [Understanding Success Criterion 1.4.13: Content on Hover or Focus](https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus.html) - remove onClick helper + - prefer the accessible name to using aria-labelledby and aria-label together These tooltips aim to follow the accessibility recommendations from: @@ -406,9 +407,10 @@ type Purpose | Disclosure -{-| Used when the content of the tooltip is the "primary label" for its content, for example, -when the trigger content is a ClickableSvg. The tooltip content will supercede the content of the trigger -HTML for screen readers. +{-| Used when the content of the tooltip is identical to the accessible name. + +For example, when using the Tooltip component with the ClickableSvg component, the Tooltip is providing +extra information to sighted users that screenreader users already have. This is the default. @@ -545,7 +547,8 @@ viewTooltip_ { trigger, id } tooltip = [ trigger ((case tooltip.purpose of PrimaryLabel -> - [ Aria.labeledBy id ] + [-- The content should already have an accessible name. + ] AuxillaryDescription -> [ Aria.describedBy [ id ] ] From 2885839d7a7c1c4cc7e578c819cf31e14ec17d36 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 16:48:41 -0700 Subject: [PATCH 08/32] Switch to table view for showing tooltip types --- styleguide-app/Examples/Tooltip.elm | 51 +++++++++++++++++++---------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index c2b70e8d..02232dba 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -21,6 +21,7 @@ import KeyboardSupport exposing (Key(..)) import Nri.Ui.ClickableSvg.V2 as ClickableSvg import Nri.Ui.ClickableText.V3 as ClickableText import Nri.Ui.Heading.V2 as Heading +import Nri.Ui.Table.V5 as Table import Nri.Ui.Text.V6 as Text import Nri.Ui.Tooltip.V3 as Tooltip import Nri.Ui.UiIcon.V1 as UiIcon @@ -86,7 +87,7 @@ example = type alias State = - { openTooltip : Maybe TooltipType + { openTooltip : Maybe TooltipId , staticExampleSettings : Control (List ( String, Tooltip.Attribute Never )) } @@ -98,14 +99,14 @@ init = } -type TooltipType +type TooltipId = PrimaryLabel | AuxillaryDescription | LearnMore type Msg - = ToggleTooltip TooltipType Bool + = ToggleTooltip TooltipId Bool | SetControl (Control (List ( String, Tooltip.Attribute Never ))) @@ -125,22 +126,38 @@ update msg model = view : EllieLink.Config -> State -> List (Html Msg) view ellieLinkConfig model = - [ Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Using the Tooltip module" ] - , Text.mediumBody - [ Text.html - [ Html.text "Label the Tooltip as either being the " - , viewPrimaryLabelTooltip model.openTooltip - , Html.text " or the " - , viewAuxillaryDescriptionToolip model.openTooltip - , Html.text " for the trigger content." - , viewToggleTip model.openTooltip - ] + [ viewCustomizableExample ellieLinkConfig model.staticExampleSettings + , Table.view + [ Table.string + { header = "Attribute" + , value = .name + , width = Css.px 50 + , cellStyles = always [] + } + , Table.custom + { header = Html.text "view" + , view = .view + , width = Css.px 50 + , cellStyles = always [] + } + ] + [ { name = "Tooltip.primaryLabel" + , view = viewPrimaryLabelTooltip model.openTooltip + , tooltipId = PrimaryLabel + } + , { name = "Tooltip.auxillaryDescription" + , view = viewAuxillaryDescriptionToolip model.openTooltip + , tooltipId = AuxillaryDescription + } + , { name = "Tooltip.toggleTip" + , view = viewToggleTip model.openTooltip + , tooltipId = LearnMore + } ] - , viewCustomizableExample ellieLinkConfig model.staticExampleSettings ] -viewPrimaryLabelTooltip : Maybe TooltipType -> Html Msg +viewPrimaryLabelTooltip : Maybe TooltipId -> Html Msg viewPrimaryLabelTooltip openTooltip = Tooltip.view { id = "tooltip__primaryLabel" @@ -162,7 +179,7 @@ viewPrimaryLabelTooltip openTooltip = ] -viewAuxillaryDescriptionToolip : Maybe TooltipType -> Html Msg +viewAuxillaryDescriptionToolip : Maybe TooltipId -> Html Msg viewAuxillaryDescriptionToolip openTooltip = Tooltip.view { id = "tooltip__auxillaryDescription" @@ -184,7 +201,7 @@ viewAuxillaryDescriptionToolip openTooltip = ] -viewToggleTip : Maybe TooltipType -> Html Msg +viewToggleTip : Maybe TooltipId -> Html Msg viewToggleTip openTooltip = Tooltip.toggleTip { label = "tooltip__learn-more" } [ Tooltip.plaintext "There's also a convenient `toggleTip` helper, for when you want to add some helpful extra info." From e871638d928be4eb4f969de11e8890ed9d35ac3b Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 17:04:34 -0700 Subject: [PATCH 09/32] Make more realistic examples of the different attribute types --- styleguide-app/Examples/Tooltip.elm | 37 ++++++++++++----------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index 02232dba..9e517cea 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -163,19 +163,17 @@ viewPrimaryLabelTooltip openTooltip = { id = "tooltip__primaryLabel" , trigger = \eventHandlers -> - ClickableText.button "primaryLabel" - [ ClickableText.custom eventHandlers + ClickableSvg.button "Download" + UiIcon.download + [ ClickableSvg.custom eventHandlers ] } - [ Tooltip.html - [ Html.text "A primary label is used when the tooltip content serves as the main label for its trigger content" - , Html.br [] - , Html.text "e.g. when the trigger content is an icon with no text." - ] - , Tooltip.auxillaryDescription + [ Tooltip.plaintext "Download" + , Tooltip.primaryLabel , Tooltip.onHover (ToggleTooltip PrimaryLabel) , Tooltip.open (openTooltip == Just PrimaryLabel) - , Tooltip.onBottom + , Tooltip.smallPadding + , Tooltip.fitToContent ] @@ -185,31 +183,26 @@ viewAuxillaryDescriptionToolip openTooltip = { id = "tooltip__auxillaryDescription" , trigger = \eventHandlers -> - ClickableText.button "auxillaryDescription" - [ ClickableText.custom eventHandlers + ClickableSvg.button "Period 1" + UiIcon.class + [ ClickableSvg.custom eventHandlers ] } - [ Tooltip.html - [ Html.text "An auxillary description is used when the tooltip content provides supplementary information about its trigger content" - , Html.br [] - , Html.text "e.g. when the trigger content is a word in the middle of a body of text that requires additional explanation." - ] + [ Tooltip.plaintext "Manage class and students" , Tooltip.auxillaryDescription , Tooltip.onHover (ToggleTooltip AuxillaryDescription) , Tooltip.open (openTooltip == Just AuxillaryDescription) - , Tooltip.onBottom + , Tooltip.smallPadding + , Tooltip.fitToContent ] viewToggleTip : Maybe TooltipId -> Html Msg viewToggleTip openTooltip = - Tooltip.toggleTip { label = "tooltip__learn-more" } - [ Tooltip.plaintext "There's also a convenient `toggleTip` helper, for when you want to add some helpful extra info." - , Tooltip.primaryLabel + Tooltip.toggleTip { label = "What is mastery?" } + [ Tooltip.plaintext "Students master topics by correctly answering a series of questions of varying difficulty and scope." , Tooltip.onHover (ToggleTooltip LearnMore) , Tooltip.open (openTooltip == Just LearnMore) - , Tooltip.smallPadding - , Tooltip.fitToContent ] From 2e019b9e00cd3338b45396da8ae55f7f4771e460 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 17:07:12 -0700 Subject: [PATCH 10/32] Add caveat for escape --- styleguide-app/Examples/Tooltip.elm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index 9e517cea..fcad1d7f 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -44,7 +44,7 @@ example = , categories = [ Messaging ] , keyboardSupport = [ { keys = [ Esc ] - , result = "Hitting escape closes all tooltips." + , result = "Hitting escape while focusing a tooltip trigger closes all tooltips. Note that hovered-but-not-focused tooltips can't be closed this way." } , { keys = [ Space ] , result = "While focusing a tooltip trigger, opens/closes the tooltip. May trigger the underlying action too." From 4e4a654d88b41b54c444489fdec2f180e09c9e0b Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 17:13:39 -0700 Subject: [PATCH 11/32] Begins adding Disclosure example --- styleguide-app/Examples/Tooltip.elm | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index fcad1d7f..538d38d9 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -20,7 +20,9 @@ import Html.Styled.Attributes exposing (css, href) import KeyboardSupport exposing (Key(..)) import Nri.Ui.ClickableSvg.V2 as ClickableSvg import Nri.Ui.ClickableText.V3 as ClickableText +import Nri.Ui.Colors.V1 as Colors import Nri.Ui.Heading.V2 as Heading +import Nri.Ui.Svg.V1 as Svg import Nri.Ui.Table.V5 as Table import Nri.Ui.Text.V6 as Text import Nri.Ui.Tooltip.V3 as Tooltip @@ -103,6 +105,7 @@ type TooltipId = PrimaryLabel | AuxillaryDescription | LearnMore + | Disclosure type Msg @@ -149,6 +152,10 @@ view ellieLinkConfig model = , view = viewAuxillaryDescriptionToolip model.openTooltip , tooltipId = AuxillaryDescription } + , { name = "Tooltip.disclosure" + , view = viewDisclosureToolip model.openTooltip + , tooltipId = Disclosure + } , { name = "Tooltip.toggleTip" , view = viewToggleTip model.openTooltip , tooltipId = LearnMore @@ -197,6 +204,31 @@ viewAuxillaryDescriptionToolip openTooltip = ] +viewDisclosureToolip : Maybe TooltipId -> Html Msg +viewDisclosureToolip openTooltip = + Tooltip.view + { id = "tooltip__disclosure" + , trigger = + \eventHandlers -> + ClickableSvg.button "Previously mastered" + (Svg.withColor Colors.green UiIcon.starFilled) + [ ClickableSvg.custom eventHandlers + ] + } + [ Tooltip.html + [ Html.text "You mastered this skill in a previous year! Way to go! " + , Html.a + [ href "https://noredink.zendesk.com/hc/en-us/articles/203022319-What-is-mastery-" ] + [ Html.text "Learn more about NoRedInk Mastery" ] + ] + , Tooltip.disclosure + , Tooltip.onHover (ToggleTooltip Disclosure) + , Tooltip.open (openTooltip == Just Disclosure) + , Tooltip.smallPadding + , Tooltip.fitToContent + ] + + viewToggleTip : Maybe TooltipId -> Html Msg viewToggleTip openTooltip = Tooltip.toggleTip { label = "What is mastery?" } From 1c524d9b91ddd4efcf7f5186a0b0dd6993b27aca Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 17:22:54 -0700 Subject: [PATCH 12/32] Adds clickablesvg click stop prop --- src/ClickableAttributes.elm | 15 ++++++++++++++- src/Nri/Ui/ClickableSvg/V2.elm | 10 ++++++++-- styleguide-app/Examples/ClickableSvg.elm | 5 ++--- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/ClickableAttributes.elm b/src/ClickableAttributes.elm index 5d0ad153..3a5af8fc 100644 --- a/src/ClickableAttributes.elm +++ b/src/ClickableAttributes.elm @@ -8,6 +8,7 @@ module ClickableAttributes exposing , linkWithMethod , linkWithTracking , onClick + , onClickStopPropagation , toButtonAttributes , toLinkAttributes ) @@ -28,6 +29,7 @@ type alias ClickableAttributes route msg = , url : Maybe route , urlString : Maybe String , onClick : Maybe msg + , stopPropagation : Bool } @@ -47,6 +49,7 @@ init = , url = Nothing , urlString = Nothing , onClick = Nothing + , stopPropagation = False } @@ -56,6 +59,12 @@ onClick msg clickableAttributes = { clickableAttributes | onClick = Just msg } +{-| -} +onClickStopPropagation : msg -> ClickableAttributes route msg -> ClickableAttributes route msg +onClickStopPropagation msg clickableAttributes = + { clickableAttributes | onClick = Just msg, stopPropagation = True } + + {-| -} href : route -> ClickableAttributes route msg -> ClickableAttributes route msg href url clickableAttributes = @@ -105,7 +114,11 @@ toButtonAttributes : ClickableAttributes route msg -> List (Attribute msg) toButtonAttributes clickableAttributes = case clickableAttributes.onClick of Just handler -> - [ Events.onClick handler ] + if clickableAttributes.stopPropagation then + [ Events.onClick handler ] + + else + [ EventExtras.onClickStopPropagation handler ] Nothing -> [] diff --git a/src/Nri/Ui/ClickableSvg/V2.elm b/src/Nri/Ui/ClickableSvg/V2.elm index 5dabb165..1319053c 100644 --- a/src/Nri/Ui/ClickableSvg/V2.elm +++ b/src/Nri/Ui/ClickableSvg/V2.elm @@ -1,7 +1,7 @@ module Nri.Ui.ClickableSvg.V2 exposing ( button, link , Attribute - , onClick + , onClick, onClickStopPropagation , href, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking , exactSize, exactWidth, exactHeight , disabled @@ -28,7 +28,7 @@ module Nri.Ui.ClickableSvg.V2 exposing ## Behavior -@docs onClick +@docs onClick, onClickStopPropagation @docs href, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking @@ -116,6 +116,12 @@ onClick msg = setClickableAttributes (ClickableAttributes.onClick msg) +{-| -} +onClickStopPropagation : msg -> Attribute msg +onClickStopPropagation msg = + setClickableAttributes (ClickableAttributes.onClickStopPropagation msg) + + {-| -} href : String -> Attribute msg href url = diff --git a/styleguide-app/Examples/ClickableSvg.elm b/styleguide-app/Examples/ClickableSvg.elm index 382e5a91..e4164cbb 100644 --- a/styleguide-app/Examples/ClickableSvg.elm +++ b/styleguide-app/Examples/ClickableSvg.elm @@ -13,7 +13,6 @@ import Css import Debug.Control as Control exposing (Control) import Debug.Control.Extra as ControlExtra import Debug.Control.View as ControlView -import EventExtras import Example exposing (Example) import Html.Styled as Html exposing (Html) import Html.Styled.Attributes as Attributes @@ -96,7 +95,7 @@ Tooltip.view ClickableSvg.button "Preview" UiIcon.preview [ ClickableSvg.custom attrs, - , ClickableSvg.custom [ EventExtras.onClickStopPropagation (ShowItWorked "You clicked the preview button!") ] + , ClickableSvg.onClickStopPropagation (ShowItWorked "You clicked the preview button!") ] , id = "preview-tooltip" } @@ -115,7 +114,7 @@ Tooltip.view ClickableSvg.button "Preview" UiIcon.preview [ ClickableSvg.custom attrs - , ClickableSvg.custom [ EventExtras.onClickStopPropagation (ShowItWorked "You clicked the preview button!") ] + , ClickableSvg.onClickStopPropagation (ShowItWorked "You clicked the preview button!") ] , id = "preview-tooltip" } From 02b219daab6f9e9eb431b6f55f4b345fc03e63c4 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 17:31:33 -0700 Subject: [PATCH 13/32] Separate the events used for disclosure versus non-disclosure pattern --- src/Nri/Ui/Tooltip/V3.elm | 32 +++++++++-------------------- styleguide-app/Examples/Tooltip.elm | 10 +++++++++ 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index 28188a71..e676ab46 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -28,21 +28,6 @@ These tooltips aim to follow the accessibility recommendations from: - - -Example usage: - - Tooltip.view - { trigger = - \attrs -> - ClickableText.button "Click me to open the tooltip" - [ ClickableText.custom attrs ] - , id = "my-tooltip" - } - [ Tooltip.plaintext "Gradebook" - , Tooltip.primaryLabel - , Tooltip.onHover MyOnTriggerMsg - , Tooltip.open True - ] - @docs view, toggleTip @docs Attribute @docs plaintext, html @@ -515,14 +500,17 @@ viewTooltip_ { trigger, id } tooltip = ( [ Events.onMouseEnter (msg True) , Events.onMouseLeave (msg False) ] - , [ Events.onFocus (msg True) + , case tooltip.purpose of + Disclosure -> + [ Events.onClick (msg (not tooltip.isOpen)) + , Key.onKeyDown [ Key.escape (msg False) ] + ] - -- TODO: this blur event means that we cannot focus links - -- that are within the tooltip without a mouse - , Events.onBlur (msg False) - , Events.onClick (msg (not tooltip.isOpen)) - , Key.onKeyDown [ Key.escape (msg False) ] - ] + _ -> + [ Events.onFocus (msg True) + , Events.onBlur (msg False) + , Key.onKeyDown [ Key.escape (msg False) ] + ] ) Nothing -> diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index 538d38d9..05586038 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -111,6 +111,7 @@ type TooltipId type Msg = ToggleTooltip TooltipId Bool | SetControl (Control (List ( String, Tooltip.Attribute Never ))) + | Log String update : Msg -> State -> ( State, Cmd Msg ) @@ -126,6 +127,13 @@ update msg model = SetControl settings -> ( { model | staticExampleSettings = settings }, Cmd.none ) + Log message -> + let + _ = + Debug.log "Tooltip Log:" message + in + ( model, Cmd.none ) + view : EllieLink.Config -> State -> List (Html Msg) view ellieLinkConfig model = @@ -173,6 +181,7 @@ viewPrimaryLabelTooltip openTooltip = ClickableSvg.button "Download" UiIcon.download [ ClickableSvg.custom eventHandlers + , ClickableSvg.onClick (Log "Fake content totally downloaded!") ] } [ Tooltip.plaintext "Download" @@ -193,6 +202,7 @@ viewAuxillaryDescriptionToolip openTooltip = ClickableSvg.button "Period 1" UiIcon.class [ ClickableSvg.custom eventHandlers + , ClickableSvg.onClick (Log "You totally started managing Periud 1.") ] } [ Tooltip.plaintext "Manage class and students" From 90bdd4c703cdcafc7f2b5fb42485814365a31713 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 17:31:46 -0700 Subject: [PATCH 14/32] Revert "Adds clickablesvg click stop prop" This reverts commit 1c524d9b91ddd4efcf7f5186a0b0dd6993b27aca. --- src/ClickableAttributes.elm | 15 +-------------- src/Nri/Ui/ClickableSvg/V2.elm | 10 ++-------- styleguide-app/Examples/ClickableSvg.elm | 5 +++-- 3 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/ClickableAttributes.elm b/src/ClickableAttributes.elm index 3a5af8fc..5d0ad153 100644 --- a/src/ClickableAttributes.elm +++ b/src/ClickableAttributes.elm @@ -8,7 +8,6 @@ module ClickableAttributes exposing , linkWithMethod , linkWithTracking , onClick - , onClickStopPropagation , toButtonAttributes , toLinkAttributes ) @@ -29,7 +28,6 @@ type alias ClickableAttributes route msg = , url : Maybe route , urlString : Maybe String , onClick : Maybe msg - , stopPropagation : Bool } @@ -49,7 +47,6 @@ init = , url = Nothing , urlString = Nothing , onClick = Nothing - , stopPropagation = False } @@ -59,12 +56,6 @@ onClick msg clickableAttributes = { clickableAttributes | onClick = Just msg } -{-| -} -onClickStopPropagation : msg -> ClickableAttributes route msg -> ClickableAttributes route msg -onClickStopPropagation msg clickableAttributes = - { clickableAttributes | onClick = Just msg, stopPropagation = True } - - {-| -} href : route -> ClickableAttributes route msg -> ClickableAttributes route msg href url clickableAttributes = @@ -114,11 +105,7 @@ toButtonAttributes : ClickableAttributes route msg -> List (Attribute msg) toButtonAttributes clickableAttributes = case clickableAttributes.onClick of Just handler -> - if clickableAttributes.stopPropagation then - [ Events.onClick handler ] - - else - [ EventExtras.onClickStopPropagation handler ] + [ Events.onClick handler ] Nothing -> [] diff --git a/src/Nri/Ui/ClickableSvg/V2.elm b/src/Nri/Ui/ClickableSvg/V2.elm index 1319053c..5dabb165 100644 --- a/src/Nri/Ui/ClickableSvg/V2.elm +++ b/src/Nri/Ui/ClickableSvg/V2.elm @@ -1,7 +1,7 @@ module Nri.Ui.ClickableSvg.V2 exposing ( button, link , Attribute - , onClick, onClickStopPropagation + , onClick , href, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking , exactSize, exactWidth, exactHeight , disabled @@ -28,7 +28,7 @@ module Nri.Ui.ClickableSvg.V2 exposing ## Behavior -@docs onClick, onClickStopPropagation +@docs onClick @docs href, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking @@ -116,12 +116,6 @@ onClick msg = setClickableAttributes (ClickableAttributes.onClick msg) -{-| -} -onClickStopPropagation : msg -> Attribute msg -onClickStopPropagation msg = - setClickableAttributes (ClickableAttributes.onClickStopPropagation msg) - - {-| -} href : String -> Attribute msg href url = diff --git a/styleguide-app/Examples/ClickableSvg.elm b/styleguide-app/Examples/ClickableSvg.elm index e4164cbb..f30115dc 100644 --- a/styleguide-app/Examples/ClickableSvg.elm +++ b/styleguide-app/Examples/ClickableSvg.elm @@ -13,6 +13,7 @@ import Css import Debug.Control as Control exposing (Control) import Debug.Control.Extra as ControlExtra import Debug.Control.View as ControlView +import EventExtras import Example exposing (Example) import Html.Styled as Html exposing (Html) import Html.Styled.Attributes as Attributes @@ -95,7 +96,7 @@ Tooltip.view ClickableSvg.button "Preview" UiIcon.preview [ ClickableSvg.custom attrs, - , ClickableSvg.onClickStopPropagation (ShowItWorked "You clicked the preview button!") + , ClickableSvg.onClick (ShowItWorked "You clicked the preview button!") ] ] , id = "preview-tooltip" } @@ -114,7 +115,7 @@ Tooltip.view ClickableSvg.button "Preview" UiIcon.preview [ ClickableSvg.custom attrs - , ClickableSvg.onClickStopPropagation (ShowItWorked "You clicked the preview button!") + , ClickableSvg.custom [ EventExtras.onClickStopPropagation (ShowItWorked "You clicked the preview button!") ] ] , id = "preview-tooltip" } From 7beb363b6eb5f13c285cae924881fbc9aa6f44a2 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 17:44:39 -0700 Subject: [PATCH 15/32] Generalize the FocusTrap module --- src/Nri/Ui/FocusTrap/V1.elm | 63 +++++-------------------- src/Nri/Ui/WhenFocusLeaves/V1.elm | 78 +++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 52 deletions(-) create mode 100644 src/Nri/Ui/WhenFocusLeaves/V1.elm diff --git a/src/Nri/Ui/FocusTrap/V1.elm b/src/Nri/Ui/FocusTrap/V1.elm index cf350f4a..3092a15b 100644 --- a/src/Nri/Ui/FocusTrap/V1.elm +++ b/src/Nri/Ui/FocusTrap/V1.elm @@ -7,8 +7,7 @@ module Nri.Ui.FocusTrap.V1 exposing (FocusTrap, toAttribute) -} import Accessibility.Styled as Html -import Html.Styled.Events as Events -import Json.Decode as Decode exposing (Decoder) +import Nri.Ui.WhenFocusLeaves.V1 as WhenFocusLeaves {-| Defines how focus will wrap in reponse to tab keypresses in a part of the UI. @@ -28,53 +27,13 @@ type alias FocusTrap msg = -} toAttribute : FocusTrap msg -> Html.Attribute msg toAttribute { firstId, lastId, focus } = - onTab <| - \elementId shiftKey -> - -- if the user tabs back while on the first id, - -- we want to wrap around to the last id. - if elementId == firstId && shiftKey then - Decode.succeed - { message = focus lastId - , preventDefault = True - , stopPropagation = False - } - - else if elementId == lastId && not shiftKey then - -- if the user tabs forward while on the last id, - -- we want to wrap around to the first id. - Decode.succeed - { message = focus firstId - , preventDefault = True - , stopPropagation = False - } - - else - Decode.fail "No need to intercept the key press" - - -onTab : - (String - -> Bool - -> Decoder { message : msg, preventDefault : Bool, stopPropagation : Bool } - ) - -> Html.Attribute msg -onTab do = - Events.custom "keydown" - (Decode.andThen - (\( id, keyCode, shiftKey ) -> - if keyCode == 9 then - do id shiftKey - - else - Decode.fail "No need to intercept the key press" - ) - decodeKeydown - ) - - -decodeKeydown : Decoder ( String, Int, Bool ) -decodeKeydown = - Decode.map3 (\id keyCode shiftKey -> ( id, keyCode, shiftKey )) - (Decode.at [ "target", "id" ] Decode.string) - (Decode.field "keyCode" Decode.int) - (Decode.field "shiftKey" Decode.bool) + WhenFocusLeaves.toAttribute + { firstId = firstId + , lastId = lastId + , -- if the user tabs back while on the first id, + -- we want to wrap around to the last id. + tabBackAction = focus lastId + , -- if the user tabs forward while on the last id, + -- we want to wrap around to the first id. + tabForwardAction = focus firstId + } diff --git a/src/Nri/Ui/WhenFocusLeaves/V1.elm b/src/Nri/Ui/WhenFocusLeaves/V1.elm new file mode 100644 index 00000000..df720984 --- /dev/null +++ b/src/Nri/Ui/WhenFocusLeaves/V1.elm @@ -0,0 +1,78 @@ +module Nri.Ui.WhenFocusLeaves.V1 exposing (toAttribute) + +{-| Listen for when the focus leaves the area, and then do an action. + +@docs toAttribute + +-} + +import Accessibility.Styled as Html +import Html.Styled.Events as Events +import Json.Decode as Decode exposing (Decoder) + + +{-| Attach this attribute to add a focus watcher to an HTML element and define +what to do in reponse to tab keypresses in a part of the UI. + +The ids referenced here are expected to correspond to elements in the container +we are adding the attribute to. + +-} +toAttribute : + { firstId : String + , lastId : String + , tabBackAction : msg + , tabForwardAction : msg + } + -> Html.Attribute msg +toAttribute { firstId, lastId, tabBackAction, tabForwardAction } = + onTab <| + \elementId shiftKey -> + -- if the user tabs back while on the first id, + -- we execute the action + if elementId == firstId && shiftKey then + Decode.succeed + { message = tabBackAction + , preventDefault = False + , stopPropagation = False + } + + else if elementId == lastId && not shiftKey then + -- if the user tabs forward while on the last id, + -- we want to wrap around to the first id. + Decode.succeed + { message = tabForwardAction + , preventDefault = False + , stopPropagation = False + } + + else + Decode.fail "No need to intercept the key press" + + +onTab : + (String + -> Bool + -> Decoder { message : msg, preventDefault : Bool, stopPropagation : Bool } + ) + -> Html.Attribute msg +onTab do = + Events.custom "keydown" + (Decode.andThen + (\( id, keyCode, shiftKey ) -> + if keyCode == 9 then + do id shiftKey + + else + Decode.fail "No need to intercept the key press" + ) + decodeKeydown + ) + + +decodeKeydown : Decoder ( String, Int, Bool ) +decodeKeydown = + Decode.map3 (\id keyCode shiftKey -> ( id, keyCode, shiftKey )) + (Decode.at [ "target", "id" ] Decode.string) + (Decode.field "keyCode" Decode.int) + (Decode.field "shiftKey" Decode.bool) From 5521d1f7ad856eff20912424d934853ec804531f Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 25 Apr 2022 17:59:24 -0700 Subject: [PATCH 16/32] Fix close-on-blur for rich disclosures --- src/Nri/Ui/Tooltip/V3.elm | 64 +++++++++++++++++++---------- styleguide-app/Examples/Tooltip.elm | 18 ++++++-- 2 files changed, 57 insertions(+), 25 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index e676ab46..765274f3 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -62,6 +62,7 @@ import Nri.Ui.Fonts.V1 as Fonts import Nri.Ui.Html.Attributes.V2 as ExtraAttributes import Nri.Ui.Shadows.V1 as Shadows import Nri.Ui.UiIcon.V1 as UiIcon +import Nri.Ui.WhenFocusLeaves.V1 as WhenFocusLeaves import String.Extra @@ -389,7 +390,7 @@ onHover msg = type Purpose = PrimaryLabel | AuxillaryDescription - | Disclosure + | Disclosure { triggerId : String, lastId : Maybe String } {-| Used when the content of the tooltip is identical to the accessible name. @@ -422,10 +423,17 @@ If clicking the "tooltip trigger" only ever shows you more info (and especially 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). +You will need to pass in the last focusable element in the disclosed content in order for: + + - any focusable elements in the disclosed content to be keyboard accessible + - the disclosure to close appropriately when the user tabs past all of the disclosed content + +You may pass a lastId of Nothing if there is NO focusable content within the disclosure. + -} -disclosure : Attribute msg -disclosure = - Attribute (\config -> { config | purpose = Disclosure }) +disclosure : { triggerId : String, lastId : Maybe String } -> Attribute msg +disclosure exitFocusManager = + Attribute (\config -> { config | purpose = Disclosure exitFocusManager }) {-| -} @@ -452,11 +460,14 @@ view config attributes = {-| Supplementary information triggered by a "?" icon. -} -toggleTip : { label : String } -> List (Attribute msg) -> Html msg -toggleTip { label } attributes_ = +toggleTip : { label : String, lastId : Maybe String } -> List (Attribute msg) -> Html msg +toggleTip { label, lastId } attributes_ = let id = String.Extra.dasherize label + + triggerId = + "tooltip-trigger__" ++ id in view { trigger = @@ -466,6 +477,7 @@ toggleTip { label } attributes_ = [ ClickableSvg.exactWidth 20 , ClickableSvg.exactHeight 20 , ClickableSvg.custom events + , ClickableSvg.id triggerId , ClickableSvg.css [ -- Take up enough room within the document flow Css.margin (Css.px 5) @@ -477,7 +489,7 @@ toggleTip { label } attributes_ = [ Attributes.class "Nri-Ui-Tooltip-V2-ToggleTip" , Attributes.id id ] - :: disclosure + :: disclosure { triggerId = triggerId, lastId = lastId } :: attributes_ ) @@ -497,21 +509,31 @@ viewTooltip_ { trigger, id } tooltip = ( containerEvents, buttonEvents ) = case tooltip.trigger of Just (OnHover msg) -> - ( [ Events.onMouseEnter (msg True) - , Events.onMouseLeave (msg False) - ] - , case tooltip.purpose of - Disclosure -> - [ Events.onClick (msg (not tooltip.isOpen)) - , Key.onKeyDown [ Key.escape (msg False) ] - ] + case tooltip.purpose of + Disclosure { triggerId, lastId } -> + ( [ Events.onMouseEnter (msg True) + , Events.onMouseLeave (msg False) + , WhenFocusLeaves.toAttribute + { firstId = triggerId + , lastId = Maybe.withDefault triggerId lastId + , tabBackAction = msg False + , tabForwardAction = msg False + } + ] + , [ Events.onClick (msg (not tooltip.isOpen)) + , Key.onKeyDown [ Key.escape (msg False) ] + ] + ) _ -> - [ Events.onFocus (msg True) - , Events.onBlur (msg False) - , Key.onKeyDown [ Key.escape (msg False) ] - ] - ) + ( [ Events.onMouseEnter (msg True) + , Events.onMouseLeave (msg False) + ] + , [ Events.onFocus (msg True) + , Events.onBlur (msg False) + , Key.onKeyDown [ Key.escape (msg False) ] + ] + ) Nothing -> ( [], [] ) @@ -541,7 +563,7 @@ viewTooltip_ { trigger, id } tooltip = AuxillaryDescription -> [ Aria.describedBy [ id ] ] - Disclosure -> + Disclosure _ -> [ Widget.expanded tooltip.isOpen , Aria.controls id ] diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index 05586038..09c74555 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -16,7 +16,7 @@ import Debug.Control.Extra as ControlExtra import Debug.Control.View as ControlView import EllieLink import Example exposing (Example) -import Html.Styled.Attributes exposing (css, href) +import Html.Styled.Attributes exposing (css, href, id) import KeyboardSupport exposing (Key(..)) import Nri.Ui.ClickableSvg.V2 as ClickableSvg import Nri.Ui.ClickableText.V3 as ClickableText @@ -216,6 +216,13 @@ viewAuxillaryDescriptionToolip openTooltip = viewDisclosureToolip : Maybe TooltipId -> Html Msg viewDisclosureToolip openTooltip = + let + triggerId = + "tooltip__disclosure-trigger" + + lastId = + "tooltip__disclosure-what-is-mastery" + in Tooltip.view { id = "tooltip__disclosure" , trigger = @@ -223,15 +230,18 @@ viewDisclosureToolip openTooltip = ClickableSvg.button "Previously mastered" (Svg.withColor Colors.green UiIcon.starFilled) [ ClickableSvg.custom eventHandlers + , ClickableSvg.id triggerId ] } [ Tooltip.html [ Html.text "You mastered this skill in a previous year! Way to go! " , Html.a - [ href "https://noredink.zendesk.com/hc/en-us/articles/203022319-What-is-mastery-" ] + [ id lastId + , href "https://noredink.zendesk.com/hc/en-us/articles/203022319-What-is-mastery-" + ] [ Html.text "Learn more about NoRedInk Mastery" ] ] - , Tooltip.disclosure + , Tooltip.disclosure { triggerId = triggerId, lastId = Just lastId } , Tooltip.onHover (ToggleTooltip Disclosure) , Tooltip.open (openTooltip == Just Disclosure) , Tooltip.smallPadding @@ -241,7 +251,7 @@ viewDisclosureToolip openTooltip = viewToggleTip : Maybe TooltipId -> Html Msg viewToggleTip openTooltip = - Tooltip.toggleTip { label = "What is mastery?" } + Tooltip.toggleTip { label = "What is mastery?", lastId = Nothing } [ Tooltip.plaintext "Students master topics by correctly answering a series of questions of varying difficulty and scope." , Tooltip.onHover (ToggleTooltip LearnMore) , Tooltip.open (openTooltip == Just LearnMore) From 7b3011e34d9fc1dd415a2f4ecd6a005bb163cd57 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 09:41:29 -0700 Subject: [PATCH 17/32] :skull: remove customTriggerAttributes --- src/Nri/Ui/Tooltip/V3.elm | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index 765274f3..b60d28cc 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -10,7 +10,7 @@ module Nri.Ui.Tooltip.V3 exposing , onHover , open , css, containerCss - , custom, customTriggerAttributes + , custom , nriDescription, testId , primaryLabel, auxillaryDescription, disclosure ) @@ -22,6 +22,7 @@ module Nri.Ui.Tooltip.V3 exposing - tooltips MUST be closable via keyboard without moving focus. [Understanding Success Criterion 1.4.13: Content on Hover or Focus](https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus.html) - remove onClick helper - prefer the accessible name to using aria-labelledby and aria-label together + - :skull: remove customTooltipAttributes These tooltips aim to follow the accessibility recommendations from: @@ -39,7 +40,7 @@ These tooltips aim to follow the accessibility recommendations from: @docs onClick, onHover @docs open @docs css, containerCss -@docs custom, customTriggerAttributes +@docs custom @docs nriDescription, testId @docs primaryLabel, auxillaryDescription, disclosure @@ -290,13 +291,6 @@ testId id_ = custom [ ExtraAttributes.testId id_ ] -{-| DEPRECATED -- a future release will remove this helper. --} -customTriggerAttributes : List (Html.Attribute msg) -> Attribute msg -customTriggerAttributes attributes = - Attribute (\config -> { config | triggerAttributes = config.triggerAttributes ++ attributes }) - - {-| -} containerCss : List Style -> Attribute msg containerCss styles = From cc049b975be402e99d57b6c12a82d7753736f335 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 09:42:19 -0700 Subject: [PATCH 18/32] fixup! :skull: remove onClick option that's discouraged by the styleguide --- src/Nri/Ui/Tooltip/V3.elm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index b60d28cc..5b602a97 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -37,7 +37,7 @@ These tooltips aim to follow the accessibility recommendations from: @docs alignStart, alignMiddle, alignEnd @docs exactWidth, fitToContent @docs smallPadding, normalPadding, customPadding -@docs onClick, onHover +@docs onHover @docs open @docs css, containerCss @docs custom From 635527c9b103e4b41046ad602d55459dba28be56 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 09:43:18 -0700 Subject: [PATCH 19/32] Change css behavior --- src/Nri/Ui/Tooltip/V3.elm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index 5b602a97..34e41783 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -23,6 +23,7 @@ module Nri.Ui.Tooltip.V3 exposing - remove onClick helper - prefer the accessible name to using aria-labelledby and aria-label together - :skull: remove customTooltipAttributes + - change `css` to extend the current list of styles, NOT override them entirely. These tooltips aim to follow the accessibility recommendations from: @@ -259,12 +260,11 @@ onLeft = withPosition OnLeft -{-| Set some custom styles on the tooltip. These will be treated as overrides, -so be careful! +{-| Set some custom styles on the tooltip. -} css : List Style -> Attribute msg css tooltipStyleOverrides = - Attribute (\config -> { config | tooltipStyleOverrides = tooltipStyleOverrides }) + Attribute (\config -> { config | tooltipStyleOverrides = config.tooltipStyleOverrides ++ tooltipStyleOverrides }) {-| Use this helper to add custom attributes. From 8fbc51b55578b9c7cc0783d29fe4d45038524271 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 09:44:45 -0700 Subject: [PATCH 20/32] Add description of --- src/Nri/Ui/Tooltip/V3.elm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index 34e41783..de10b865 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -430,7 +430,8 @@ disclosure exitFocusManager = Attribute (\config -> { config | purpose = Disclosure exitFocusManager }) -{-| -} +{-| Pass a bool indicating whether the tooltip should be open or closed. +-} open : Bool -> Attribute msg open isOpen = Attribute (\config -> { config | isOpen = isOpen }) From 1971ae8d2fda6632b4dea22f7681534e1797f548 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 09:54:14 -0700 Subject: [PATCH 21/32] Fix spelling of auxiliary --- src/Nri/Ui/Tooltip/V1.elm | 8 ++++---- src/Nri/Ui/Tooltip/V2.elm | 10 +++++----- src/Nri/Ui/Tooltip/V3.elm | 9 +++++---- styleguide-app/Examples/SegmentedControl.elm | 1 + styleguide-app/Examples/Tooltip.elm | 6 +++--- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V1.elm b/src/Nri/Ui/Tooltip/V1.elm index 686b7cbb..59919b3e 100644 --- a/src/Nri/Ui/Tooltip/V1.elm +++ b/src/Nri/Ui/Tooltip/V1.elm @@ -5,7 +5,7 @@ module Nri.Ui.Tooltip.V1 exposing , Padding(..), withPadding , withTooltipStyleOverrides , Trigger(..) - , primaryLabel, auxillaryDescription, toggleTip + , primaryLabel, auxiliaryDescription, toggleTip ) {-| A tooltip component! @@ -51,7 +51,7 @@ Example usage: ## View Functions -@docs primaryLabel, auxillaryDescription, toggleTip +@docs primaryLabel, auxiliaryDescription, toggleTip -} @@ -215,7 +215,7 @@ primaryLabel = {-| Used when the content of the tooltip provides an "auxillary description" for its content. -} -auxillaryDescription : +auxiliaryDescription : { trigger : Trigger , triggerHtml : Html msg , extraButtonAttrs : List (Attribute msg) @@ -225,7 +225,7 @@ auxillaryDescription : } -> Tooltip msg -> Html msg -auxillaryDescription = +auxiliaryDescription = viewTooltip_ AuxillaryDescription diff --git a/src/Nri/Ui/Tooltip/V2.elm b/src/Nri/Ui/Tooltip/V2.elm index 1444baed..72d2629d 100644 --- a/src/Nri/Ui/Tooltip/V2.elm +++ b/src/Nri/Ui/Tooltip/V2.elm @@ -12,7 +12,7 @@ module Nri.Ui.Tooltip.V2 exposing , css, containerCss , custom, customTriggerAttributes , nriDescription, testId - , primaryLabel, auxillaryDescription + , primaryLabel, auxiliaryDescription ) {-| Known issues: @@ -40,7 +40,7 @@ Changes from V1: - adds plaintext, html helpers for setting the content - pass a list of attributes rather than requiring a pipeline to set up the tooltip - move Trigger into the attributes - - change primaryLabel and auxillaryDescription to attributes, adding view + - change primaryLabel and auxiliaryDescription to attributes, adding view - move the onTrigger event to the attributes - extraButtonAttrs becomes attribute `customTriggerAttributes` - isOpen field becomes the `open` attribute @@ -77,7 +77,7 @@ Example usage: @docs css, containerCss @docs custom, customTriggerAttributes @docs nriDescription, testId -@docs primaryLabel, auxillaryDescription +@docs primaryLabel, auxiliaryDescription -} @@ -450,8 +450,8 @@ primaryLabel = {-| Used when the content of the tooltip provides an "auxillary description" for its content. -} -auxillaryDescription : Attribute msg -auxillaryDescription = +auxiliaryDescription : Attribute msg +auxiliaryDescription = Attribute (\config -> { config | purpose = AuxillaryDescription }) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index de10b865..33eaf142 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -12,7 +12,7 @@ module Nri.Ui.Tooltip.V3 exposing , css, containerCss , custom , nriDescription, testId - , primaryLabel, auxillaryDescription, disclosure + , primaryLabel, auxiliaryDescription, disclosure ) {-| Changes from V2: @@ -24,6 +24,7 @@ module Nri.Ui.Tooltip.V3 exposing - prefer the accessible name to using aria-labelledby and aria-label together - :skull: remove customTooltipAttributes - change `css` to extend the current list of styles, NOT override them entirely. + - fix spelling of "auxillary" to "auxiliary" These tooltips aim to follow the accessibility recommendations from: @@ -43,7 +44,7 @@ These tooltips aim to follow the accessibility recommendations from: @docs css, containerCss @docs custom @docs nriDescription, testId -@docs primaryLabel, auxillaryDescription, disclosure +@docs primaryLabel, auxiliaryDescription, disclosure -} @@ -406,8 +407,8 @@ An auxillary description is used when the tooltip content provides supplementary e.g. when the trigger content is a word in the middle of a body of text that requires additional explanation. -} -auxillaryDescription : Attribute msg -auxillaryDescription = +auxiliaryDescription : Attribute msg +auxiliaryDescription = Attribute (\config -> { config | purpose = AuxillaryDescription }) diff --git a/styleguide-app/Examples/SegmentedControl.elm b/styleguide-app/Examples/SegmentedControl.elm index 4e714dc4..712683d8 100644 --- a/styleguide-app/Examples/SegmentedControl.elm +++ b/styleguide-app/Examples/SegmentedControl.elm @@ -309,6 +309,7 @@ buildRadioOptions options currentlyHovered content = Nothing ) ) + , Tooltip.auxiliaryDescription ] else diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index 09c74555..064e5760 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -156,7 +156,7 @@ view ellieLinkConfig model = , view = viewPrimaryLabelTooltip model.openTooltip , tooltipId = PrimaryLabel } - , { name = "Tooltip.auxillaryDescription" + , { name = "Tooltip.auxiliaryDescription" , view = viewAuxillaryDescriptionToolip model.openTooltip , tooltipId = AuxillaryDescription } @@ -196,7 +196,7 @@ viewPrimaryLabelTooltip openTooltip = viewAuxillaryDescriptionToolip : Maybe TooltipId -> Html Msg viewAuxillaryDescriptionToolip openTooltip = Tooltip.view - { id = "tooltip__auxillaryDescription" + { id = "tooltip__auxiliaryDescription" , trigger = \eventHandlers -> ClickableSvg.button "Period 1" @@ -206,7 +206,7 @@ viewAuxillaryDescriptionToolip openTooltip = ] } [ Tooltip.plaintext "Manage class and students" - , Tooltip.auxillaryDescription + , Tooltip.auxiliaryDescription , Tooltip.onHover (ToggleTooltip AuxillaryDescription) , Tooltip.open (openTooltip == Just AuxillaryDescription) , Tooltip.smallPadding From 66355b0763e5753a36743c09858a19435c5ed769 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 10:03:04 -0700 Subject: [PATCH 22/32] Rename toggleTip -> viewToggleTip --- src/Nri/Ui/Tooltip/V3.elm | 9 +++++---- styleguide-app/Examples/Tooltip.elm | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index 33eaf142..5612ecfd 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -1,5 +1,5 @@ module Nri.Ui.Tooltip.V3 exposing - ( view, toggleTip + ( view, viewToggleTip , Attribute , plaintext, html , withoutTail @@ -25,13 +25,14 @@ module Nri.Ui.Tooltip.V3 exposing - :skull: remove customTooltipAttributes - change `css` to extend the current list of styles, NOT override them entirely. - fix spelling of "auxillary" to "auxiliary" + - toggleTip -> viewToggleTip These tooltips aim to follow the accessibility recommendations from: - - -@docs view, toggleTip +@docs view, viewToggleTip @docs Attribute @docs plaintext, html @docs withoutTail @@ -456,8 +457,8 @@ view config attributes = {-| Supplementary information triggered by a "?" icon. -} -toggleTip : { label : String, lastId : Maybe String } -> List (Attribute msg) -> Html msg -toggleTip { label, lastId } attributes_ = +viewToggleTip : { label : String, lastId : Maybe String } -> List (Attribute msg) -> Html msg +viewToggleTip { label, lastId } attributes_ = let id = String.Extra.dasherize label diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index 064e5760..a5005f8e 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -164,7 +164,7 @@ view ellieLinkConfig model = , view = viewDisclosureToolip model.openTooltip , tooltipId = Disclosure } - , { name = "Tooltip.toggleTip" + , { name = "Tooltip.viewToggleTip" , view = viewToggleTip model.openTooltip , tooltipId = LearnMore } @@ -251,7 +251,7 @@ viewDisclosureToolip openTooltip = viewToggleTip : Maybe TooltipId -> Html Msg viewToggleTip openTooltip = - Tooltip.toggleTip { label = "What is mastery?", lastId = Nothing } + Tooltip.viewToggleTip { label = "What is mastery?", lastId = Nothing } [ Tooltip.plaintext "Students master topics by correctly answering a series of questions of varying difficulty and scope." , Tooltip.onHover (ToggleTooltip LearnMore) , Tooltip.open (openTooltip == Just LearnMore) From 3a737400e9c390c7d5b63701e2ec90db04788d07 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 10:05:52 -0700 Subject: [PATCH 23/32] Adds non-desktop style helpers --- src/Nri/Ui/Tooltip/V3.elm | 46 +++++++++++++++++++++++++++-- styleguide-app/Examples/Tooltip.elm | 4 +++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index 5612ecfd..f5ff24ca 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -9,7 +9,7 @@ module Nri.Ui.Tooltip.V3 exposing , smallPadding, normalPadding, customPadding , onHover , open - , css, containerCss + , css, notMobileCss, mobileCss, quizEngineMobileCss, containerCss , custom , nriDescription, testId , primaryLabel, auxiliaryDescription, disclosure @@ -26,6 +26,7 @@ module Nri.Ui.Tooltip.V3 exposing - change `css` to extend the current list of styles, NOT override them entirely. - fix spelling of "auxillary" to "auxiliary" - toggleTip -> viewToggleTip + - Adds notMobileCss, mobileCss, quizEngineMobileCss These tooltips aim to follow the accessibility recommendations from: @@ -42,7 +43,7 @@ These tooltips aim to follow the accessibility recommendations from: @docs smallPadding, normalPadding, customPadding @docs onHover @docs open -@docs css, containerCss +@docs css, notMobileCss, mobileCss, quizEngineMobileCss, containerCss @docs custom @docs nriDescription, testId @docs primaryLabel, auxiliaryDescription, disclosure @@ -56,6 +57,7 @@ import Accessibility.Styled.Role as Role import Accessibility.Styled.Widget as Widget import Css exposing (Color, Px, Style) import Css.Global as Global +import Css.Media exposing (withMedia) import Html.Styled as Root import Html.Styled.Attributes as Attributes import Html.Styled.Events as Events @@ -64,6 +66,7 @@ import Nri.Ui.ClickableSvg.V2 as ClickableSvg import Nri.Ui.Colors.V1 as Colors import Nri.Ui.Fonts.V1 as Fonts import Nri.Ui.Html.Attributes.V2 as ExtraAttributes +import Nri.Ui.MediaQuery.V1 as MediaQuery import Nri.Ui.Shadows.V1 as Shadows import Nri.Ui.UiIcon.V1 as UiIcon import Nri.Ui.WhenFocusLeaves.V1 as WhenFocusLeaves @@ -269,6 +272,45 @@ css tooltipStyleOverrides = Attribute (\config -> { config | tooltipStyleOverrides = config.tooltipStyleOverrides ++ tooltipStyleOverrides }) +{-| Set styles that will only apply if the viewport is wider than NRI's mobile breakpoint. + +Equivalent to: + + Tooltip.css + [ Css.Media.withMedia [ Nri.Ui.MediaQuery.V1.notMobile ] styles ] + +-} +notMobileCss : List Style -> Attribute msg +notMobileCss styles = + css [ Css.Media.withMedia [ MediaQuery.notMobile ] styles ] + + +{-| Set styles that will only apply if the viewport is narrower than NRI's mobile breakpoint. + +Equivalent to: + + Tooltip.css + [ Css.Media.withMedia [ Nri.Ui.MediaQuery.V1.mobile ] styles ] + +-} +mobileCss : List Style -> Attribute msg +mobileCss styles = + css [ Css.Media.withMedia [ MediaQuery.mobile ] styles ] + + +{-| Set styles that will only apply if the viewport is narrower than NRI's quiz-engine-specific mobile breakpoint. + +Equivalent to: + + Tooltip.css + [ Css.Media.withMedia [ Nri.Ui.MediaQuery.V1.quizEngineMobile ] styles ] + +-} +quizEngineMobileCss : List Style -> Attribute msg +quizEngineMobileCss styles = + css [ Css.Media.withMedia [ MediaQuery.quizEngineMobile ] styles ] + + {-| Use this helper to add custom attributes. Do NOT use this helper to add css styles, as they may not be applied the way diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index a5005f8e..279d2e69 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -267,6 +267,10 @@ initStaticExampleSettings = |> ControlExtra.optionalBoolListItem "withoutTail" ( "Tooltip.withoutTail", Tooltip.withoutTail ) |> ControlExtra.optionalListItem "width" controlWidth |> ControlExtra.optionalListItem "padding" controlPadding + |> CommonControls.css { moduleName = moduleName, use = Tooltip.css } + |> CommonControls.mobileCss { moduleName = moduleName, use = Tooltip.mobileCss } + |> CommonControls.quizEngineMobileCss { moduleName = moduleName, use = Tooltip.quizEngineMobileCss } + |> CommonControls.notMobileCss { moduleName = moduleName, use = Tooltip.notMobileCss } controlContent : Control ( String, Tooltip.Attribute Never ) From e8872549b55f7f8260b39f1c9860bbe787b28e70 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 10:20:02 -0700 Subject: [PATCH 24/32] Extend API to include alignment and direction mobile options (which aren't yet implemented) --- src/Nri/Ui/Tooltip/V3.elm | 109 ++++++++++++++++++++++++++++ styleguide-app/Examples/Tooltip.elm | 37 ++++++++++ 2 files changed, 146 insertions(+) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index f5ff24ca..29ca881b 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -4,7 +4,9 @@ module Nri.Ui.Tooltip.V3 exposing , plaintext, html , withoutTail , onTop, onBottom, onLeft, onRight + , onTopForMobile, onBottomForMobile, onLeftForMobile, onRightForMobile , alignStart, alignMiddle, alignEnd + , alignStartForMobile, alignMiddleForMobile, alignEndForMobile , exactWidth, fitToContent , smallPadding, normalPadding, customPadding , onHover @@ -38,7 +40,9 @@ These tooltips aim to follow the accessibility recommendations from: @docs plaintext, html @docs withoutTail @docs onTop, onBottom, onLeft, onRight +@docs onTopForMobile, onBottomForMobile, onLeftForMobile, onRightForMobile @docs alignStart, alignMiddle, alignEnd +@docs alignStartForMobile, alignMiddleForMobile, alignEndForMobile @docs exactWidth, fitToContent @docs smallPadding, normalPadding, customPadding @docs onHover @@ -81,6 +85,8 @@ type Attribute msg type alias Tooltip msg = { direction : Direction , alignment : Alignment + , mobileDirection : Direction + , mobileAlignment : Alignment , tail : Tail , content : List (Html msg) , attributes : List (Html.Attribute Never) @@ -102,6 +108,8 @@ buildAttributes = defaultTooltip = { direction = OnTop , alignment = Middle + , mobileDirection = OnTop + , mobileAlignment = Middle , tail = WithTail , content = [] , attributes = [] @@ -200,6 +208,51 @@ alignEnd position = withAligment (End position) +withMobileAligment : Alignment -> Attribute msg +withMobileAligment alignment = + Attribute (\config -> { config | mobileAlignment = alignment }) + + +{-| Put the tail at the "start" of the tooltip when the viewport has a mobile width. +For onTop & onBottom tooltips, this means "left". +For onLeft & onRight tooltip, this means "top". + + __________ + |_ ______| + \/ + +-} +alignStartForMobile : Px -> Attribute msg +alignStartForMobile position = + withMobileAligment (Start position) + + +{-| Put the tail at the "middle" of the tooltip when the viewport has a mobile width. This is the default behavior. + + __________ + |___ ____| + \/ + +-} +alignMiddleForMobile : Attribute msg +alignMiddleForMobile = + withMobileAligment Middle + + +{-| Put the tail at the "end" of the tooltip when the viewport has a mobile width. +For onTop & onBottom tooltips, this means "right". +For onLeft & onRight tooltip, this means "bottom". + + __________ + |______ _| + \/ + +-} +alignEndForMobile : Px -> Attribute msg +alignEndForMobile position = + withMobileAligment (End position) + + {-| Where should this tooltip be positioned relative to the trigger? -} type Direction @@ -265,6 +318,62 @@ onLeft = withPosition OnLeft +withPositionForMobile : Direction -> Attribute msg +withPositionForMobile direction = + Attribute (\config -> { config | mobileDirection = direction }) + + +{-| Set the position of the tooltip when the mobile breakpoint applies. + + __________ + | | + |___ ____| + \/ + +-} +onTopForMobile : Attribute msg +onTopForMobile = + withPositionForMobile OnTop + + +{-| Set the position of the tooltip when the mobile breakpoint applies. + + __________ + | | + < | + |_________| + +-} +onRightForMobile : Attribute msg +onRightForMobile = + withPositionForMobile OnRight + + +{-| Set the position of the tooltip when the mobile breakpoint applies. + + ___/\_____ + | | + |_________| + +-} +onBottomForMobile : Attribute msg +onBottomForMobile = + withPositionForMobile OnBottom + + +{-| Set the position of the tooltip when the mobile breakpoint applies. + + __________ + | | + | > + |_________| + +-} +onLeftForMobile : Attribute msg +onLeftForMobile = + withPositionForMobile OnLeft + + {-| Set some custom styles on the tooltip. -} css : List Style -> Attribute msg diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index 279d2e69..9ac1102a 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -263,7 +263,9 @@ initStaticExampleSettings = ControlExtra.list |> ControlExtra.listItem "content" controlContent |> ControlExtra.optionalListItem "direction" controlDirection + |> ControlExtra.optionalListItem "direction -- mobile" controlDirectionForMobile |> ControlExtra.optionalListItem "alignment" controlAlignment + |> ControlExtra.optionalListItem "alignment -- mobile" controlAlignmentForMobile |> ControlExtra.optionalBoolListItem "withoutTail" ( "Tooltip.withoutTail", Tooltip.withoutTail ) |> ControlExtra.optionalListItem "width" controlWidth |> ControlExtra.optionalListItem "padding" controlPadding @@ -294,6 +296,16 @@ controlDirection = ] +controlDirectionForMobile : Control ( String, Tooltip.Attribute Never ) +controlDirectionForMobile = + CommonControls.choice "Tooltip" + [ ( "onTopForMobile", Tooltip.onTopForMobile ) + , ( "onBottomForMobile", Tooltip.onBottomForMobile ) + , ( "onLeftForMobile", Tooltip.onLeftForMobile ) + , ( "onRightForMobile", Tooltip.onRightForMobile ) + ] + + controlAlignment : Control ( String, Tooltip.Attribute Never ) controlAlignment = Control.choice @@ -319,6 +331,31 @@ controlAlignment = ] +controlAlignmentForMobile : Control ( String, Tooltip.Attribute Never ) +controlAlignmentForMobile = + Control.choice + [ ( "alignMiddleForMobile (default)", Control.value ( "Tooltip.alignMiddleForMobile", Tooltip.alignMiddleForMobile ) ) + , ( "alignStartForMobile" + , Control.map + (\float -> + ( "Tooltip.alignStartForMobile (Css.px " ++ String.fromFloat float ++ ")" + , Tooltip.alignStartForMobile (Css.px float) + ) + ) + (ControlExtra.float 0) + ) + , ( "alignEndForMobile" + , Control.map + (\float -> + ( "Tooltip.alignEndForMobile (Css.px " ++ String.fromFloat float ++ ")" + , Tooltip.alignEndForMobile (Css.px float) + ) + ) + (ControlExtra.float 0) + ) + ] + + controlWidth : Control ( String, Tooltip.Attribute Never ) controlWidth = Control.choice From 29f53ee92bf36bee2ea2d40e06db5d013aaca733 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 14:22:25 -0700 Subject: [PATCH 25/32] Implement mobile-specific tooltip positioning --- src/Nri/Ui/Tooltip/V3.elm | 94 +++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index 29ca881b..1bdf2db8 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -784,7 +784,10 @@ viewTooltip tooltipId config = Html.div [ Attributes.css [ Css.position Css.absolute - , positionTooltip config.direction config.alignment + , Css.Media.withMedia [ MediaQuery.notMobile ] + (positionTooltip config.direction config.alignment) + , Css.Media.withMedia [ MediaQuery.mobile ] + (positionTooltip config.mobileDirection config.mobileAlignment) , Css.boxSizing Css.borderBox , if config.isOpen then Css.batch [] @@ -806,10 +809,36 @@ viewTooltip tooltipId config = , paddingToStyle config.padding , Css.position Css.absolute , Css.zIndex (Css.int 100) + , Css.backgroundColor Colors.navy + , Css.border3 (Css.px 1) Css.solid Colors.navy + , Css.Media.withMedia [ MediaQuery.notMobile ] + [ positioning config.direction config.alignment + , case config.tail of + WithTail -> + tailForDirection config.direction + + WithoutTail -> + Css.batch [] + ] + , Css.Media.withMedia [ MediaQuery.mobile ] + [ positioning config.mobileDirection config.mobileAlignment + , case config.tail of + WithTail -> + tailForDirection config.mobileDirection + + WithoutTail -> + Css.batch [] + ] + , Fonts.baseFont + , Css.fontSize (Css.px 16) + , Css.fontWeight (Css.int 600) + , Css.color Colors.white + , Shadows.high + , Global.descendants [ Global.a [ Css.textDecoration Css.underline ] ] + , Global.descendants [ Global.a [ Css.color Colors.white ] ] ] ++ config.tooltipStyleOverrides ) - , pointerBox config.tail config.direction config.alignment -- We need to keep this animation in tests to make it pass: check out -- the NoAnimations middleware. So if you change the name here, please @@ -839,9 +868,9 @@ offCenterOffset = 20 -{-| This returns an absolute positioning style attribute for the popout container for a given tail position. +{-| This returns absolute positioning styles for the popout container for a given tail position. -} -positionTooltip : Direction -> Alignment -> Style +positionTooltip : Direction -> Alignment -> List Style positionTooltip direction alignment = let ltrPosition = @@ -866,49 +895,26 @@ positionTooltip direction alignment = End customOffset -> Css.bottom customOffset in - Css.batch <| - case direction of - OnTop -> - [ ltrPosition - , Css.top (Css.calc (Css.px (negate tailSize)) Css.minus (Css.px 2)) - ] + case direction of + OnTop -> + [ ltrPosition + , Css.top (Css.calc (Css.px (negate tailSize)) Css.minus (Css.px 2)) + ] - OnBottom -> - [ ltrPosition - , Css.bottom (Css.calc (Css.px (negate tailSize)) Css.minus (Css.px 2)) - ] + OnBottom -> + [ ltrPosition + , Css.bottom (Css.calc (Css.px (negate tailSize)) Css.minus (Css.px 2)) + ] - OnLeft -> - [ topToBottomPosition - , Css.left (Css.calc (Css.px (negate tailSize)) Css.minus (Css.px 2)) - ] + OnLeft -> + [ topToBottomPosition + , Css.left (Css.calc (Css.px (negate tailSize)) Css.minus (Css.px 2)) + ] - OnRight -> - [ topToBottomPosition - , Css.right (Css.calc (Css.px (negate tailSize)) Css.minus (Css.px 2)) - ] - - -pointerBox : Tail -> Direction -> Alignment -> Html.Attribute msg -pointerBox tail direction alignment = - Attributes.css - [ Css.backgroundColor Colors.navy - , Css.border3 (Css.px 1) Css.solid Colors.navy - , positioning direction alignment - , case tail of - WithTail -> - tailForDirection direction - - WithoutTail -> - Css.batch [] - , Fonts.baseFont - , Css.fontSize (Css.px 16) - , Css.fontWeight (Css.int 600) - , Css.color Colors.white - , Shadows.high - , Global.descendants [ Global.a [ Css.textDecoration Css.underline ] ] - , Global.descendants [ Global.a [ Css.color Colors.white ] ] - ] + OnRight -> + [ topToBottomPosition + , Css.right (Css.calc (Css.px (negate tailSize)) Css.minus (Css.px 2)) + ] From b8320aa001c46156afa3c40a9b5489a2297e8172 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 14:31:03 -0700 Subject: [PATCH 26/32] Sneak around elm review error --- src/Nri/Ui/Tooltip/V3.elm | 2 +- styleguide-app/Examples/Tooltip.elm | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index 1bdf2db8..25cc59b4 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -61,7 +61,7 @@ import Accessibility.Styled.Role as Role import Accessibility.Styled.Widget as Widget import Css exposing (Color, Px, Style) import Css.Global as Global -import Css.Media exposing (withMedia) +import Css.Media import Html.Styled as Root import Html.Styled.Attributes as Attributes import Html.Styled.Events as Events diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index 9ac1102a..aa57dfe4 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -19,12 +19,9 @@ import Example exposing (Example) import Html.Styled.Attributes exposing (css, href, id) import KeyboardSupport exposing (Key(..)) import Nri.Ui.ClickableSvg.V2 as ClickableSvg -import Nri.Ui.ClickableText.V3 as ClickableText import Nri.Ui.Colors.V1 as Colors -import Nri.Ui.Heading.V2 as Heading import Nri.Ui.Svg.V1 as Svg import Nri.Ui.Table.V5 as Table -import Nri.Ui.Text.V6 as Text import Nri.Ui.Tooltip.V3 as Tooltip import Nri.Ui.UiIcon.V1 as UiIcon @@ -128,11 +125,7 @@ update msg model = ( { model | staticExampleSettings = settings }, Cmd.none ) Log message -> - let - _ = - Debug.log "Tooltip Log:" message - in - ( model, Cmd.none ) + ( Debug.log "Tooltip Log:" |> always model, Cmd.none ) view : EllieLink.Config -> State -> List (Html Msg) From 781ebc0941d9fcea5ce3b30536a4f15f2b37da0b Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 14:40:30 -0700 Subject: [PATCH 27/32] Hide redundant info from screenreader users --- src/Nri/Ui/Tooltip/V3.elm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index 25cc59b4..17465fd1 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -721,9 +721,6 @@ viewTooltip_ { trigger, id } tooltip = ) , hoverBridge tooltip ] - - -- Popout is rendered after the overlay, to allow client code to give it - -- priority when clicking by setting its position , viewTooltip id tooltip ] @@ -795,6 +792,10 @@ viewTooltip tooltipId config = else Css.display Css.none ] + , -- If the tooltip is the "primary label" for the content, then we can trust that the content + -- in the tooltip is redundant. For example, if we have a ClickableSvg "Print" button, the button will + -- *already have* an accessible name. It is not helpful to have the "Print" read out twice. + Widget.hidden (config.purpose == PrimaryLabel) ] [ Html.div ([ Attributes.css From a15a7f24f9150f5fe5471461e9893898b45b579f Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 14:51:56 -0700 Subject: [PATCH 28/32] Improve documentation/explanation --- src/Nri/Ui/Tooltip/V3.elm | 8 +++--- styleguide-app/Examples/Tooltip.elm | 40 +++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index 17465fd1..15f836c6 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -553,10 +553,9 @@ primaryLabel = Attribute (\config -> { config | purpose = PrimaryLabel }) -{-| Used when the content of the tooltip provides an "auxillary description" for its content. +{-| Used when the content of the tooltip provides an "auxiliary description" for its content. -An auxillary description is used when the tooltip content provides supplementary information about its trigger content -e.g. when the trigger content is a word in the middle of a body of text that requires additional explanation. +An auxiliary description is used when the tooltip content provides supplementary information about its trigger content. -} auxiliaryDescription : Attribute msg @@ -607,6 +606,9 @@ view config attributes = {-| Supplementary information triggered by a "?" icon. + +This is a helper for setting up a commonly-used `disclosure` tooltip. Please see the documentation for `disclosure` to learn more. + -} viewToggleTip : { label : String, lastId : Maybe String } -> List (Attribute msg) -> Html msg viewToggleTip { label, lastId } attributes_ = diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index aa57dfe4..e954d39f 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -18,6 +18,7 @@ import EllieLink import Example exposing (Example) import Html.Styled.Attributes exposing (css, href, id) import KeyboardSupport exposing (Key(..)) +import Markdown import Nri.Ui.ClickableSvg.V2 as ClickableSvg import Nri.Ui.Colors.V1 as Colors import Nri.Ui.Svg.V1 as Svg @@ -135,29 +136,64 @@ view ellieLinkConfig model = [ Table.string { header = "Attribute" , value = .name - , width = Css.px 50 + , width = Css.pct 15 + , cellStyles = always [] + } + , Table.custom + { header = Html.text "About" + , view = .description >> Markdown.toHtml Nothing >> List.map Html.fromUnstyled >> Html.span [] + , width = Css.px 200 , cellStyles = always [] } , Table.custom { header = Html.text "view" , view = .view , width = Css.px 50 - , cellStyles = always [] + , cellStyles = always [ Css.textAlign Css.center ] } ] [ { name = "Tooltip.primaryLabel" + , description = + """ +Used when the content of the tooltip is identical to the accessible name. + +For example, when using the Tooltip component with the ClickableSvg component, the Tooltip is providing +extra information to sighted users that screenreader users already have. + +This is the default. +""" , view = viewPrimaryLabelTooltip model.openTooltip , tooltipId = PrimaryLabel } , { name = "Tooltip.auxiliaryDescription" + , description = + """ +Used when the content of the tooltip provides an "auxiliary description" for its content. + +An auxiliary description is used when the tooltip content provides supplementary information about its trigger content. +""" , view = viewAuxillaryDescriptionToolip model.openTooltip , tooltipId = AuxillaryDescription } , { name = "Tooltip.disclosure" + , description = + """ +Sometimes a "tooltip" only _looks_ like a tooltip, but is really more about hiding and showing extra information when the user asks for it. + +If clicking the "tooltip trigger" only ever shows you more info (and especially if this info is rich or interactable), use this attribute. + +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). +""" , view = viewDisclosureToolip model.openTooltip , tooltipId = Disclosure } , { name = "Tooltip.viewToggleTip" + , description = + """ +Supplementary information triggered by a "?" icon. + +This is a helper for setting up a commonly-used `disclosure` tooltip. Please see the documentation for `disclosure` to learn more. +""" , view = viewToggleTip model.openTooltip , tooltipId = LearnMore } From 3546f0efa60d11bc132213e4427dfc3930b94138 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 14:57:39 -0700 Subject: [PATCH 29/32] Improve examples --- styleguide-app/Examples/Tooltip.elm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index e954d39f..c7617b58 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -240,6 +240,7 @@ viewAuxillaryDescriptionToolip openTooltip = , Tooltip.open (openTooltip == Just AuxillaryDescription) , Tooltip.smallPadding , Tooltip.fitToContent + , Tooltip.onLeftForMobile ] @@ -274,7 +275,7 @@ viewDisclosureToolip openTooltip = , Tooltip.onHover (ToggleTooltip Disclosure) , Tooltip.open (openTooltip == Just Disclosure) , Tooltip.smallPadding - , Tooltip.fitToContent + , Tooltip.alignEndForMobile (Css.px 148) ] @@ -284,6 +285,7 @@ viewToggleTip openTooltip = [ Tooltip.plaintext "Students master topics by correctly answering a series of questions of varying difficulty and scope." , Tooltip.onHover (ToggleTooltip LearnMore) , Tooltip.open (openTooltip == Just LearnMore) + , Tooltip.alignEndForMobile (Css.px 144) ] From 0784360952583d6e963961b0f2ed3f4b6bfbd5ea Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 15:12:50 -0700 Subject: [PATCH 30/32] Expose when focus leaves module --- elm.json | 1 + tests/elm-verify-examples.json | 1 + 2 files changed, 2 insertions(+) diff --git a/elm.json b/elm.json index e3554bf3..6ea70c31 100644 --- a/elm.json +++ b/elm.json @@ -25,6 +25,7 @@ "Nri.Ui.DisclosureIndicator.V2", "Nri.Ui.Divider.V2", "Nri.Ui.Effects.V1", + "Nri.Ui.WhenFocusLeaves.V1", "Nri.Ui.FocusTrap.V1", "Nri.Ui.Fonts.V1", "Nri.Ui.Heading.V2", diff --git a/tests/elm-verify-examples.json b/tests/elm-verify-examples.json index a5bd7147..1b73957f 100644 --- a/tests/elm-verify-examples.json +++ b/tests/elm-verify-examples.json @@ -21,6 +21,7 @@ "Nri.Ui.DisclosureIndicator.V2", "Nri.Ui.Divider.V2", "Nri.Ui.Effects.V1", + "Nri.Ui.WhenFocusLeaves.V1", "Nri.Ui.FocusTrap.V1", "Nri.Ui.Fonts.V1", "Nri.Ui.Heading.V2", From f07b544a81827b7011bec396bb209724d9330b63 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 15:33:02 -0700 Subject: [PATCH 31/32] Update specs --- src/Nri/Ui/Tooltip/V3.elm | 7 +++ tests/Spec/Nri/Ui/Tooltip.elm | 93 ++++++++++------------------------- 2 files changed, 32 insertions(+), 68 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index 15f836c6..c976a37b 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -794,6 +794,13 @@ viewTooltip tooltipId config = else Css.display Css.none ] + , -- Used for tests, since the visibility is controlled via CSS, which elm-program-test cannot account for + Attributes.attribute "data-tooltip-visible" <| + if config.isOpen then + "true" + + else + "false" , -- If the tooltip is the "primary label" for the content, then we can trust that the content -- in the tooltip is redundant. For example, if we have a ClickableSvg "Print" button, the button will -- *already have* an accessible name. It is not helpful to have the "Print" read out twice. diff --git a/tests/Spec/Nri/Ui/Tooltip.elm b/tests/Spec/Nri/Ui/Tooltip.elm index 9d4ed129..c9a9a1ee 100644 --- a/tests/Spec/Nri/Ui/Tooltip.elm +++ b/tests/Spec/Nri/Ui/Tooltip.elm @@ -1,21 +1,20 @@ module Spec.Nri.Ui.Tooltip exposing (spec) -import Accessibility.Aria as Aria import Accessibility.Widget as Widget import Html.Attributes as Attributes import Html.Styled as HtmlStyled -import Nri.Ui.Tooltip.V2 as Tooltip -import ProgramTest exposing (ProgramTest, clickButton, ensureViewHas, ensureViewHasNot) +import Nri.Ui.Tooltip.V3 as Tooltip +import ProgramTest exposing (ProgramTest, ensureViewHas, ensureViewHasNot) import Test exposing (..) import Test.Html.Event as Event import Test.Html.Query as Query -import Test.Html.Selector as Selector exposing (id, tag, text) +import Test.Html.Selector as Selector exposing (id, text) spec : Test spec = - describe "Nri.Ui.Tooltip.V2" - [ test "Tooltip.toggleTip with onHover trigger" <| + describe "Nri.Ui.Tooltip.V3" + [ test "Tooltip.viewToggleTip" <| \() -> let tooltipContent = @@ -24,60 +23,24 @@ spec = label = "More info" in - program (Tooltip.toggleTip { label = label }) + program (Tooltip.viewToggleTip { label = label, lastId = Nothing }) [ Tooltip.plaintext tooltipContent , Tooltip.onHover identity ] -- Tooltip opens on mouse enter |> mouseEnter [ nriDescription "Nri-Ui-Tooltip-V2" ] - |> ensureViewHas [ text tooltipContent ] - -- Tooltip stays open on trigger-html click + |> ensureViewHas (tooltipContentSelector tooltipContent) + -- Tooltip closes on trigger-html click |> clickButtonByLabel label - |> ensureViewHas [ text tooltipContent ] + |> ensureViewHasNot (tooltipContentSelector tooltipContent) + -- Tooltip reopens on trigger-html click + |> clickButtonByLabel label + |> ensureViewHas (tooltipContentSelector tooltipContent) -- Tooltip closes on mouse leave |> mouseLeave [ nriDescription "Nri-Ui-Tooltip-V2" ] - |> ensureViewHasNot [ text tooltipContent ] - -- Tooltip opens on focus - |> focus [ tag "button", Selector.attribute (Widget.label label) ] - |> ensureViewHas [ text tooltipContent ] - -- Tooltip closes on blur - |> blur [ tag "button", Selector.attribute (Widget.label label) ] - |> ensureViewHasNot [ text tooltipContent ] + |> ensureViewHasNot (tooltipContentSelector tooltipContent) |> ProgramTest.done - , test "Tooltip.view with onClick trigger" <| - \() -> - let - tooltipContent = - "This will be the primary label" - - triggerContent = - "label-less icon" - - tooltipId = - "primary-label" - in - program - (Tooltip.view - { trigger = \events -> HtmlStyled.button events [ HtmlStyled.text triggerContent ] - , id = tooltipId - } - ) - [ Tooltip.plaintext tooltipContent - , Tooltip.primaryLabel - , Tooltip.onClick identity - ] - -- Tooltip opens on click - |> clickButton triggerContent - |> ensureViewHas - [ tag "button" - , Selector.attribute (Aria.labeledBy tooltipId) - ] - |> ensureViewHas [ id tooltipId, text tooltipContent ] - -- Tooltip closes on another click - |> clickButton triggerContent - |> ensureViewHasNot [ id tooltipId, text tooltipContent ] - |> ProgramTest.done - , test "Tooltip.view with onHover trigger" <| + , test "Tooltip.view" <| \() -> let tooltipContent = @@ -101,35 +64,22 @@ spec = ] -- Tooltip opens on mouse enter |> mouseEnter [ nriDescription "Nri-Ui-Tooltip-V2" ] - |> ensureViewHas [ text tooltipContent ] - -- Tooltip stays open on trigger-html click - |> clickButton triggerContent - |> ensureViewHas [ text tooltipContent ] + |> ensureViewHas (tooltipContentSelector tooltipContent) -- Tooltip closes on mouse leave |> mouseLeave [ nriDescription "Nri-Ui-Tooltip-V2" ] - |> ensureViewHasNot [ text tooltipContent ] + |> ensureViewHasNot (tooltipContentSelector tooltipContent) -- Tooltip opens on focus |> focus [ Selector.tag "button" , Selector.containing [ Selector.text triggerContent ] ] - |> ProgramTest.ensureViewHas - [ tag "button" - , Selector.attribute (Aria.labeledBy tooltipId) - ] - |> ProgramTest.ensureViewHas - [ id tooltipId - , Selector.text tooltipContent - ] + |> ProgramTest.ensureViewHas (tooltipContentSelector tooltipContent) -- Tooltip closes on blur |> blur [ Selector.tag "button" , Selector.containing [ Selector.text triggerContent ] ] - |> ProgramTest.ensureViewHasNot - [ id tooltipId - , Selector.text tooltipContent - ] + |> ProgramTest.ensureViewHasNot (id tooltipId :: tooltipContentSelector tooltipContent) |> ProgramTest.done ] @@ -149,6 +99,13 @@ program view attributes = |> ProgramTest.start () +tooltipContentSelector : String -> List Selector.Selector +tooltipContentSelector tooltipContent = + [ Selector.attribute (Attributes.attribute "data-tooltip-visible" "true") + , Selector.containing [ text tooltipContent ] + ] + + nriDescription : String -> Selector.Selector nriDescription desc = Selector.attribute (Attributes.attribute "data-nri-description" desc) From fdd80784355d8d4186715332bdd33005f91d0d16 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 2 May 2022 15:40:11 -0700 Subject: [PATCH 32/32] onHover -> onToggle --- src/Nri/Ui/Tooltip/V2.elm | 10 +++++----- src/Nri/Ui/Tooltip/V3.elm | 18 +++++++++++++----- styleguide-app/Examples/ClickableSvg.elm | 4 ++-- styleguide-app/Examples/SegmentedControl.elm | 8 ++++---- styleguide-app/Examples/Tabs.elm | 4 ++-- styleguide-app/Examples/Tooltip.elm | 8 ++++---- tests/Spec/Nri/Ui/Tooltip.elm | 4 ++-- 7 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/Nri/Ui/Tooltip/V2.elm b/src/Nri/Ui/Tooltip/V2.elm index 72d2629d..eafa4e24 100644 --- a/src/Nri/Ui/Tooltip/V2.elm +++ b/src/Nri/Ui/Tooltip/V2.elm @@ -7,7 +7,7 @@ module Nri.Ui.Tooltip.V2 exposing , alignStart, alignMiddle, alignEnd , exactWidth, fitToContent , smallPadding, normalPadding, customPadding - , onClick, onHover + , onClick, onToggle , open , css, containerCss , custom, customTriggerAttributes @@ -18,7 +18,7 @@ module Nri.Ui.Tooltip.V2 exposing {-| Known issues: - tooltips with focusable content (e.g., a link) will not handle focus correctly for - keyboard-only users when using the onHover attribute + keyboard-only users when using the onToggle attribute Post-release patches: @@ -72,7 +72,7 @@ Example usage: @docs alignStart, alignMiddle, alignEnd @docs exactWidth, fitToContent @docs smallPadding, normalPadding, customPadding -@docs onClick, onHover +@docs onClick, onToggle @docs open @docs css, containerCss @docs custom, customTriggerAttributes @@ -419,8 +419,8 @@ type Trigger msg {-| The tooltip opens when hovering over the trigger element, and closes when the hover stops. -} -onHover : (Bool -> msg) -> Attribute msg -onHover msg = +onToggle : (Bool -> msg) -> Attribute msg +onToggle msg = Attribute (\config -> { config | trigger = Just (OnHover msg) }) diff --git a/src/Nri/Ui/Tooltip/V3.elm b/src/Nri/Ui/Tooltip/V3.elm index c976a37b..18d13a75 100644 --- a/src/Nri/Ui/Tooltip/V3.elm +++ b/src/Nri/Ui/Tooltip/V3.elm @@ -9,7 +9,7 @@ module Nri.Ui.Tooltip.V3 exposing , alignStartForMobile, alignMiddleForMobile, alignEndForMobile , exactWidth, fitToContent , smallPadding, normalPadding, customPadding - , onHover + , onToggle , open , css, notMobileCss, mobileCss, quizEngineMobileCss, containerCss , custom @@ -29,6 +29,7 @@ module Nri.Ui.Tooltip.V3 exposing - fix spelling of "auxillary" to "auxiliary" - toggleTip -> viewToggleTip - Adds notMobileCss, mobileCss, quizEngineMobileCss + - onHover -> onToggle These tooltips aim to follow the accessibility recommendations from: @@ -45,7 +46,7 @@ These tooltips aim to follow the accessibility recommendations from: @docs alignStartForMobile, alignMiddleForMobile, alignEndForMobile @docs exactWidth, fitToContent @docs smallPadding, normalPadding, customPadding -@docs onHover +@docs onToggle @docs open @docs css, notMobileCss, mobileCss, quizEngineMobileCss, containerCss @docs custom @@ -527,10 +528,17 @@ type Trigger msg = OnHover (Bool -> msg) -{-| The tooltip opens when hovering over the trigger element, and closes when the hover stops. +{-| The Tooltip event cycle depends on whether you're following the Disclosure pattern, but disguising the Disclosure as a tooltip visually or you're actually adding a hint or label for sighted users. + +If you're adding a tooltip to an element that _does_ something on its own, e.g., a "Print" ClickableSvg, then it doesn't make sense for the tooltip to change state on click/enter/space. + +However, if you're adding a tooltip to an element that is not interactive at all if you don't count the tooltip, then we can use the click/enter/space events to manage the tooltip state too. This style of "tooltip" is the only kind that will be accessible for touch users on mobile -- it's important to get the access pattern right! + +If the tooltip behavior you're seeing doesn't _feel_ quite right, consider whether you need to change tooltip "types" to `disclosure` or to `auxiliaryDescription`. + -} -onHover : (Bool -> msg) -> Attribute msg -onHover msg = +onToggle : (Bool -> msg) -> Attribute msg +onToggle msg = Attribute (\config -> { config | trigger = Just (OnHover msg) }) diff --git a/styleguide-app/Examples/ClickableSvg.elm b/styleguide-app/Examples/ClickableSvg.elm index f30115dc..4f8d8bd4 100644 --- a/styleguide-app/Examples/ClickableSvg.elm +++ b/styleguide-app/Examples/ClickableSvg.elm @@ -102,7 +102,7 @@ Tooltip.view } [ Tooltip.plaintext "Preview" , Tooltip.primaryLabel - , Tooltip.onHover SetPreviewTooltip + , Tooltip.onToggle SetPreviewTooltip , Tooltip.open state.tooltipPreview , Tooltip.smallPadding , Tooltip.fitToContent @@ -121,7 +121,7 @@ Tooltip.view } [ Tooltip.plaintext "Preview" , Tooltip.primaryLabel - , Tooltip.onHover SetPreviewTooltip + , Tooltip.onToggle SetPreviewTooltip , Tooltip.open state.tooltipPreview , Tooltip.smallPadding , Tooltip.fitToContent diff --git a/styleguide-app/Examples/SegmentedControl.elm b/styleguide-app/Examples/SegmentedControl.elm index 712683d8..b871dff9 100644 --- a/styleguide-app/Examples/SegmentedControl.elm +++ b/styleguide-app/Examples/SegmentedControl.elm @@ -206,7 +206,7 @@ buildOptions { content, longContent, tooltips } openTooltip = , ", tabTooltip = " ++ (if tooltips then ("\n\t\t[ Tooltip.plaintext " ++ valueStr) - ++ ("\n\t\t, Tooltip.onHover (OpenTooltip " ++ valueStr ++ ")") + ++ ("\n\t\t, Tooltip.onToggle (OpenTooltip " ++ valueStr ++ ")") ++ ("\n\t\t, Tooltip.open (openTooltip == Just " ++ valueStr ++ ")") ++ "\n\t\t]" @@ -225,7 +225,7 @@ buildOptions { content, longContent, tooltips } openTooltip = , tabTooltip = if tooltips then [ Tooltip.plaintext (Debug.toString value) - , Tooltip.onHover (PageTooltip value) + , Tooltip.onToggle (PageTooltip value) , Tooltip.open (openTooltip == Just value) ] @@ -279,7 +279,7 @@ buildRadioOptions options currentlyHovered content = , ", tooltip = " ++ (if options.tooltips then ("\n\t\t[ Tooltip.plaintext " ++ String.fromInt value) - ++ ("\n\t\t, Tooltip.onHover (OpenTooltip " ++ String.fromInt value ++ ")") + ++ ("\n\t\t, Tooltip.onToggle (OpenTooltip " ++ String.fromInt value ++ ")") ++ ("\n\t\t, Tooltip.open (openTooltip == Just " ++ String.fromInt value ++ ")") ++ "\n\t\t]" @@ -299,7 +299,7 @@ buildRadioOptions options currentlyHovered content = [ Tooltip.plaintext text , Tooltip.open (currentlyHovered == Just value) , Tooltip.fitToContent - , Tooltip.onHover + , Tooltip.onToggle (\hovered -> HoverRadio (if hovered then diff --git a/styleguide-app/Examples/Tabs.elm b/styleguide-app/Examples/Tabs.elm index d4633233..ee387528 100644 --- a/styleguide-app/Examples/Tabs.elm +++ b/styleguide-app/Examples/Tabs.elm @@ -221,7 +221,7 @@ allTabs openTooltipId labelledBy = , Tabs.tabString "1" , Tabs.withTooltip [ Tooltip.plaintext "Link Example" - , Tooltip.onHover (ToggleTooltip First) + , Tooltip.onToggle (ToggleTooltip First) , Tooltip.alignStart (Css.px 75) , Tooltip.primaryLabel , Tooltip.open (openTooltipId == Just First) @@ -245,7 +245,7 @@ allTabs openTooltipId labelledBy = [ Tabs.tabHtml bulbIcon , Tabs.withTooltip [ Tooltip.plaintext "The Electrifying Third Tab" - , Tooltip.onHover (ToggleTooltip Third) + , Tooltip.onToggle (ToggleTooltip Third) , Tooltip.primaryLabel , Tooltip.open (openTooltipId == Just Third) ] diff --git a/styleguide-app/Examples/Tooltip.elm b/styleguide-app/Examples/Tooltip.elm index c7617b58..1c129d35 100644 --- a/styleguide-app/Examples/Tooltip.elm +++ b/styleguide-app/Examples/Tooltip.elm @@ -215,7 +215,7 @@ viewPrimaryLabelTooltip openTooltip = } [ Tooltip.plaintext "Download" , Tooltip.primaryLabel - , Tooltip.onHover (ToggleTooltip PrimaryLabel) + , Tooltip.onToggle (ToggleTooltip PrimaryLabel) , Tooltip.open (openTooltip == Just PrimaryLabel) , Tooltip.smallPadding , Tooltip.fitToContent @@ -236,7 +236,7 @@ viewAuxillaryDescriptionToolip openTooltip = } [ Tooltip.plaintext "Manage class and students" , Tooltip.auxiliaryDescription - , Tooltip.onHover (ToggleTooltip AuxillaryDescription) + , Tooltip.onToggle (ToggleTooltip AuxillaryDescription) , Tooltip.open (openTooltip == Just AuxillaryDescription) , Tooltip.smallPadding , Tooltip.fitToContent @@ -272,7 +272,7 @@ viewDisclosureToolip openTooltip = [ Html.text "Learn more about NoRedInk Mastery" ] ] , Tooltip.disclosure { triggerId = triggerId, lastId = Just lastId } - , Tooltip.onHover (ToggleTooltip Disclosure) + , Tooltip.onToggle (ToggleTooltip Disclosure) , Tooltip.open (openTooltip == Just Disclosure) , Tooltip.smallPadding , Tooltip.alignEndForMobile (Css.px 148) @@ -283,7 +283,7 @@ viewToggleTip : Maybe TooltipId -> Html Msg viewToggleTip openTooltip = Tooltip.viewToggleTip { label = "What is mastery?", lastId = Nothing } [ Tooltip.plaintext "Students master topics by correctly answering a series of questions of varying difficulty and scope." - , Tooltip.onHover (ToggleTooltip LearnMore) + , Tooltip.onToggle (ToggleTooltip LearnMore) , Tooltip.open (openTooltip == Just LearnMore) , Tooltip.alignEndForMobile (Css.px 144) ] diff --git a/tests/Spec/Nri/Ui/Tooltip.elm b/tests/Spec/Nri/Ui/Tooltip.elm index c9a9a1ee..ffe39c44 100644 --- a/tests/Spec/Nri/Ui/Tooltip.elm +++ b/tests/Spec/Nri/Ui/Tooltip.elm @@ -25,7 +25,7 @@ spec = in program (Tooltip.viewToggleTip { label = label, lastId = Nothing }) [ Tooltip.plaintext tooltipContent - , Tooltip.onHover identity + , Tooltip.onToggle identity ] -- Tooltip opens on mouse enter |> mouseEnter [ nriDescription "Nri-Ui-Tooltip-V2" ] @@ -60,7 +60,7 @@ spec = ) [ Tooltip.plaintext tooltipContent , Tooltip.primaryLabel - , Tooltip.onHover identity + , Tooltip.onToggle identity ] -- Tooltip opens on mouse enter |> mouseEnter [ nriDescription "Nri-Ui-Tooltip-V2" ]