Merge pull request #918 from NoRedInk/bat/mobile-friendly-tooltip

Tooltip.V3
This commit is contained in:
Alex Perkins 2022-05-04 11:41:26 -04:00 committed by GitHub
commit b3e32ffed8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1483 additions and 228 deletions

View File

@ -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

1 Nri.Ui.Accordion.V1 upgrade to V3
10 Nri.Ui.Switch.V1 upgrade to V2
11 Nri.Ui.Table.V4 upgrade to V5
12 Nri.Ui.Tabs.V6 upgrade to V7
13 Nri.Ui.Tooltip.V1 upgrade to V2 upgrade to V3
14 Nri.Ui.Tooltip.V2 upgrade to V3

View File

@ -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",
@ -72,6 +73,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",

View File

@ -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'

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -7,18 +7,18 @@ module Nri.Ui.Tooltip.V2 exposing
, alignStart, alignMiddle, alignEnd
, exactWidth, fitToContent
, smallPadding, normalPadding, customPadding
, onClick, onHover
, onClick, onToggle
, open
, css, containerCss
, custom, customTriggerAttributes
, nriDescription, testId
, primaryLabel, auxillaryDescription
, primaryLabel, auxiliaryDescription
)
{-| 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:
@ -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
@ -72,12 +72,12 @@ 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
@docs nriDescription, testId
@docs primaryLabel, auxillaryDescription
@docs primaryLabel, auxiliaryDescription
-}
@ -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) })
@ -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 })

1103
src/Nri/Ui/Tooltip/V3.elm Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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)

View File

@ -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)

View File

@ -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
@ -96,13 +96,13 @@ Tooltip.view
ClickableSvg.button "Preview"
UiIcon.preview
[ ClickableSvg.custom attrs,
, ClickableSvg.custom [ EventExtras.onClickStopPropagation (ShowItWorked "You clicked the preview button!") ]
, ClickableSvg.onClick (ShowItWorked "You clicked the preview button!") ]
]
, id = "preview-tooltip"
}
[ 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

View File

@ -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
@ -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
@ -309,6 +309,7 @@ buildRadioOptions options currentlyHovered content =
Nothing
)
)
, Tooltip.auxiliaryDescription
]
else

View File

@ -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
@ -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)
]

View File

@ -16,18 +16,25 @@ 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 Markdown
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.Colors.V1 as Colors
import Nri.Ui.Svg.V1 as Svg
import Nri.Ui.Table.V5 as Table
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
@ -35,7 +42,17 @@ example =
{ name = moduleName
, version = version
, categories = [ Messaging ]
, keyboardSupport = []
, keyboardSupport =
[ { keys = [ Esc ]
, 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."
}
, { 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
@ -69,13 +86,8 @@ example =
}
moduleName : String
moduleName =
"Tooltip"
type alias State =
{ openTooltip : Maybe TooltipType
{ openTooltip : Maybe TooltipId
, staticExampleSettings : Control (List ( String, Tooltip.Attribute Never ))
}
@ -87,15 +99,17 @@ init =
}
type TooltipType
type TooltipId
= PrimaryLabel
| AuxillaryDescription
| LearnMore
| Disclosure
type Msg
= ToggleTooltip TooltipType Bool
= ToggleTooltip TooltipId Bool
| SetControl (Control (List ( String, Tooltip.Attribute Never )))
| Log String
update : Msg -> State -> ( State, Cmd Msg )
@ -111,93 +125,185 @@ update msg model =
SetControl settings ->
( { model | staticExampleSettings = settings }, Cmd.none )
Log message ->
( Debug.log "Tooltip Log:" |> always model, Cmd.none )
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.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 [ 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
}
]
, viewCustomizableExample ellieLinkConfig model.staticExampleSettings
]
viewPrimaryLabelTooltip : Maybe TooltipType -> Html Msg
viewPrimaryLabelTooltip : Maybe TooltipId -> Html Msg
viewPrimaryLabelTooltip openTooltip =
Tooltip.view
{ id = "tooltip__primaryLabel"
, trigger =
\eventHandlers ->
ClickableText.button "primaryLabel"
[ ClickableText.custom eventHandlers
ClickableSvg.button "Download"
UiIcon.download
[ ClickableSvg.custom eventHandlers
, ClickableSvg.onClick (Log "Fake content totally downloaded!")
]
}
[ 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.onHover (ToggleTooltip PrimaryLabel)
, Tooltip.open (openTooltip == Just PrimaryLabel)
, Tooltip.onBottom
]
viewAuxillaryDescriptionToolip : Maybe TooltipType -> Html Msg
viewAuxillaryDescriptionToolip openTooltip =
Tooltip.view
{ id = "tooltip__auxillaryDescription"
, trigger =
\eventHandlers ->
ClickableText.button "auxillaryDescription"
[ ClickableText.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.auxillaryDescription
, Tooltip.onHover (ToggleTooltip AuxillaryDescription)
, Tooltip.open (openTooltip == Just AuxillaryDescription)
, Tooltip.onBottom
]
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 "Download"
, Tooltip.primaryLabel
, Tooltip.onHover (ToggleTooltip LearnMore)
, Tooltip.open (openTooltip == Just LearnMore)
, Tooltip.onToggle (ToggleTooltip PrimaryLabel)
, Tooltip.open (openTooltip == Just PrimaryLabel)
, Tooltip.smallPadding
, Tooltip.fitToContent
]
viewAuxillaryDescriptionToolip : Maybe TooltipId -> Html Msg
viewAuxillaryDescriptionToolip openTooltip =
Tooltip.view
{ id = "tooltip__auxiliaryDescription"
, trigger =
\eventHandlers ->
ClickableSvg.button "Period 1"
UiIcon.class
[ ClickableSvg.custom eventHandlers
, ClickableSvg.onClick (Log "You totally started managing Periud 1.")
]
}
[ Tooltip.plaintext "Manage class and students"
, Tooltip.auxiliaryDescription
, Tooltip.onToggle (ToggleTooltip AuxillaryDescription)
, Tooltip.open (openTooltip == Just AuxillaryDescription)
, Tooltip.smallPadding
, Tooltip.fitToContent
, Tooltip.onLeftForMobile
]
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 =
\eventHandlers ->
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
[ id lastId
, href "https://noredink.zendesk.com/hc/en-us/articles/203022319-What-is-mastery-"
]
[ Html.text "Learn more about NoRedInk Mastery" ]
]
, Tooltip.disclosure { triggerId = triggerId, lastId = Just lastId }
, Tooltip.onToggle (ToggleTooltip Disclosure)
, Tooltip.open (openTooltip == Just Disclosure)
, Tooltip.smallPadding
, Tooltip.alignEndForMobile (Css.px 148)
]
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.onToggle (ToggleTooltip LearnMore)
, Tooltip.open (openTooltip == Just LearnMore)
, Tooltip.alignEndForMobile (Css.px 144)
]
initStaticExampleSettings : Control (List ( String, Tooltip.Attribute Never ))
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
|> 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 )
@ -221,6 +327,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
@ -246,6 +362,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

View File

@ -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,27 +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.onToggle 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" <|
, test "Tooltip.view" <|
\() ->
let
tooltipContent =
@ -64,72 +60,26 @@ spec =
)
[ 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" <|
\() ->
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.onHover identity
, Tooltip.onToggle identity
]
-- 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)

View File

@ -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",
@ -68,6 +69,7 @@
"Nri.Ui.TextInput.V7",
"Nri.Ui.Tooltip.V1",
"Nri.Ui.Tooltip.V2",
"Nri.Ui.Tooltip.V3",
"Nri.Ui.UiIcon.V1"
]
}