mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-11-05 00:29:17 +03:00
Merge pull request #1333 from NoRedInk/bat/highlighter-toolbar-radio-inputs
🔧 Use radio inputs under the hood in HighlighterToolbar
This commit is contained in:
commit
d85105928f
@ -6,7 +6,6 @@ module Examples.HighlighterToolbar exposing (Msg, State, example)
|
||||
|
||||
-}
|
||||
|
||||
import Browser.Dom as Dom
|
||||
import Category exposing (Category(..))
|
||||
import Code
|
||||
import Css exposing (Color)
|
||||
@ -18,11 +17,10 @@ import Html.Styled.Attributes exposing (css, id)
|
||||
import KeyboardSupport exposing (Key(..))
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.HighlighterToolbar.V2 as HighlighterToolbar
|
||||
import Nri.Ui.HighlighterToolbar.V3 as HighlighterToolbar
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
import Task
|
||||
|
||||
|
||||
moduleName : String
|
||||
@ -32,7 +30,7 @@ moduleName =
|
||||
|
||||
version : Int
|
||||
version =
|
||||
2
|
||||
3
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -60,13 +58,29 @@ example =
|
||||
, mainType = Nothing
|
||||
, extraCode = []
|
||||
, renderExample = Code.unstyledView
|
||||
, toExampleCode = \_ -> []
|
||||
, toExampleCode =
|
||||
\_ ->
|
||||
[ { sectionName = "Example"
|
||||
, code =
|
||||
Code.fromModule moduleName "view"
|
||||
++ Code.recordMultiline
|
||||
[ ( "onSelect", "identity -- msg for selecting the tag or eraser" )
|
||||
, ( "getNameAndColor", "identity" )
|
||||
, ( "highlighterId", Code.string "highlighter-id" )
|
||||
]
|
||||
2
|
||||
++ Code.recordMultiline
|
||||
[ ( "currentTool", "Nothing" )
|
||||
, ( "tags", "[]" )
|
||||
]
|
||||
2
|
||||
}
|
||||
]
|
||||
}
|
||||
, Heading.h2 [ Heading.plaintext "Example" ]
|
||||
, HighlighterToolbar.view
|
||||
{ focusAndSelect = FocusAndSelectTag
|
||||
, getColor = getColor
|
||||
, getName = getName
|
||||
{ onSelect = SelectTag
|
||||
, getNameAndColor = identity
|
||||
, highlighterId = "highlighter"
|
||||
}
|
||||
{ currentTool = state.currentTool
|
||||
@ -111,47 +125,28 @@ toolPreview color border icon name =
|
||||
]
|
||||
|
||||
|
||||
type Tag
|
||||
= Claim
|
||||
| Evidence
|
||||
| Reasoning
|
||||
type alias Tag =
|
||||
{ name : String
|
||||
, colorSolid : Css.Color
|
||||
, colorLight : Css.Color
|
||||
}
|
||||
|
||||
|
||||
tags : List Tag
|
||||
tags =
|
||||
[ Claim, Evidence, Reasoning ]
|
||||
|
||||
|
||||
getName : Tag -> String
|
||||
getName tag =
|
||||
case tag of
|
||||
Claim ->
|
||||
"Claim"
|
||||
|
||||
Evidence ->
|
||||
"Evidence"
|
||||
|
||||
Reasoning ->
|
||||
"Reasoning"
|
||||
|
||||
|
||||
getColor : Tag -> { colorSolid : Color, colorLight : Color }
|
||||
getColor tag =
|
||||
case tag of
|
||||
Claim ->
|
||||
{ colorSolid = Colors.mustard
|
||||
, colorLight = Colors.highlightYellow
|
||||
}
|
||||
|
||||
Evidence ->
|
||||
{ colorSolid = Colors.magenta
|
||||
, colorLight = Colors.highlightMagenta
|
||||
}
|
||||
|
||||
Reasoning ->
|
||||
{ colorSolid = Colors.cyan
|
||||
, colorLight = Colors.highlightCyan
|
||||
}
|
||||
[ { name = "Claim"
|
||||
, colorSolid = Colors.mustard
|
||||
, colorLight = Colors.highlightYellow
|
||||
}
|
||||
, { name = "Evidence"
|
||||
, colorSolid = Colors.magenta
|
||||
, colorLight = Colors.highlightMagenta
|
||||
}
|
||||
, { name = "Reasoning"
|
||||
, colorSolid = Colors.cyan
|
||||
, colorLight = Colors.highlightCyan
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -185,8 +180,7 @@ controlSettings =
|
||||
{-| -}
|
||||
type Msg
|
||||
= UpdateControls (Control Settings)
|
||||
| FocusAndSelectTag { select : Maybe Tag, focus : Maybe String }
|
||||
| Focused (Result Dom.Error ())
|
||||
| SelectTag (Maybe Tag)
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -196,12 +190,7 @@ update msg state =
|
||||
UpdateControls settings ->
|
||||
( { state | settings = settings }, Cmd.none )
|
||||
|
||||
FocusAndSelectTag { select, focus } ->
|
||||
( { state | currentTool = select }
|
||||
, focus
|
||||
|> Maybe.map (Dom.focus >> Task.attempt Focused)
|
||||
|> Maybe.withDefault Cmd.none
|
||||
SelectTag newTool ->
|
||||
( { state | currentTool = newTool }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
Focused error ->
|
||||
( state, Cmd.none )
|
||||
|
@ -9,26 +9,27 @@
|
||||
"elm/core": "1.0.5",
|
||||
"elm/json": "1.1.3",
|
||||
"elm/project-metadata-utils": "1.0.2",
|
||||
"jfmengels/elm-review": "2.7.0",
|
||||
"jfmengels/elm-review-unused": "1.1.20",
|
||||
"jfmengels/elm-review": "2.12.2",
|
||||
"jfmengels/elm-review-unused": "1.1.29",
|
||||
"stil4m/elm-syntax": "7.2.9"
|
||||
},
|
||||
"indirect": {
|
||||
"elm/bytes": "1.0.8",
|
||||
"elm/html": "1.0.0",
|
||||
"elm/parser": "1.1.0",
|
||||
"elm/random": "1.0.0",
|
||||
"elm/time": "1.0.0",
|
||||
"elm/virtual-dom": "1.0.2",
|
||||
"elm-community/list-extra": "8.5.2",
|
||||
"elm-explorations/test": "1.2.2",
|
||||
"miniBill/elm-unicode": "1.0.2",
|
||||
"elm/virtual-dom": "1.0.3",
|
||||
"elm-community/list-extra": "8.7.0",
|
||||
"elm-explorations/test": "2.1.1",
|
||||
"miniBill/elm-unicode": "1.0.3",
|
||||
"rtfeldman/elm-hex": "1.0.0",
|
||||
"stil4m/structured-writer": "1.0.3"
|
||||
}
|
||||
},
|
||||
"test-dependencies": {
|
||||
"direct": {
|
||||
"elm-explorations/test": "1.2.2"
|
||||
"elm-explorations/test": "2.1.1"
|
||||
},
|
||||
"indirect": {}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
Nri.Ui.Block.V3,upgrade to V4
|
||||
Nri.Ui.Highlightable.V1,upgrade to V2
|
||||
Nri.Ui.Highlighter.V2,upgrade to V3
|
||||
Nri.Ui.HighlighterToolbar.V1,upgrade to V2
|
||||
Nri.Ui.HighlighterToolbar.V1,upgrade to V3
|
||||
Nri.Ui.HighlighterToolbar.V2,upgrade to V3
|
||||
Nri.Ui.QuestionBox.V2,upgrade to V4
|
||||
Nri.Ui.QuestionBox.V3,upgrade to V4
|
||||
Nri.Ui.Select.V8,upgrade to V9
|
||||
|
|
1
elm.json
1
elm.json
@ -41,6 +41,7 @@
|
||||
"Nri.Ui.HighlighterTool.V1",
|
||||
"Nri.Ui.HighlighterToolbar.V1",
|
||||
"Nri.Ui.HighlighterToolbar.V2",
|
||||
"Nri.Ui.HighlighterToolbar.V3",
|
||||
"Nri.Ui.Html.Attributes.V2",
|
||||
"Nri.Ui.Html.V3",
|
||||
"Nri.Ui.InputStyles.V4",
|
||||
|
@ -88,7 +88,10 @@ hint = 'upgrade to V2'
|
||||
hint = 'upgrade to V3'
|
||||
|
||||
[forbidden."Nri.Ui.HighlighterToolbar.V1"]
|
||||
hint = 'upgrade to V2'
|
||||
hint = 'upgrade to V3'
|
||||
|
||||
[forbidden."Nri.Ui.HighlighterToolbar.V2"]
|
||||
hint = 'upgrade to V3'
|
||||
|
||||
[forbidden."Nri.Ui.Icon.V3"]
|
||||
hint = 'upgrade to V5'
|
||||
|
@ -9,26 +9,27 @@
|
||||
"elm/core": "1.0.5",
|
||||
"elm/json": "1.1.3",
|
||||
"elm/project-metadata-utils": "1.0.2",
|
||||
"jfmengels/elm-review": "2.7.0",
|
||||
"jfmengels/elm-review-unused": "1.1.20",
|
||||
"jfmengels/elm-review": "2.12.2",
|
||||
"jfmengels/elm-review-unused": "1.1.29",
|
||||
"stil4m/elm-syntax": "7.2.9"
|
||||
},
|
||||
"indirect": {
|
||||
"elm/bytes": "1.0.8",
|
||||
"elm/html": "1.0.0",
|
||||
"elm/parser": "1.1.0",
|
||||
"elm/random": "1.0.0",
|
||||
"elm/time": "1.0.0",
|
||||
"elm/virtual-dom": "1.0.2",
|
||||
"elm-community/list-extra": "8.5.2",
|
||||
"elm-explorations/test": "1.2.2",
|
||||
"miniBill/elm-unicode": "1.0.2",
|
||||
"elm/virtual-dom": "1.0.3",
|
||||
"elm-community/list-extra": "8.7.0",
|
||||
"elm-explorations/test": "2.1.1",
|
||||
"miniBill/elm-unicode": "1.0.3",
|
||||
"rtfeldman/elm-hex": "1.0.0",
|
||||
"stil4m/structured-writer": "1.0.3"
|
||||
}
|
||||
},
|
||||
"test-dependencies": {
|
||||
"direct": {
|
||||
"elm-explorations/test": "1.2.2"
|
||||
"elm-explorations/test": "2.1.1"
|
||||
},
|
||||
"indirect": {}
|
||||
}
|
||||
|
210
src/Nri/Ui/HighlighterToolbar/V3.elm
Normal file
210
src/Nri/Ui/HighlighterToolbar/V3.elm
Normal file
@ -0,0 +1,210 @@
|
||||
module Nri.Ui.HighlighterToolbar.V3 exposing (view)
|
||||
|
||||
{-| Bar with markers for choosing how text will be highlighted in a highlighter.
|
||||
|
||||
@docs view
|
||||
|
||||
|
||||
### Changes from V2:
|
||||
|
||||
- Use radio inputs under the hood
|
||||
- don't arbitrarily complicate API -- match the usecases on the monolith side
|
||||
|
||||
|
||||
### Patch changes:
|
||||
|
||||
- Ensure selected tool is clear in high contrast mode
|
||||
|
||||
|
||||
### Changes from V1:
|
||||
|
||||
- replaces `onChangeTag` and `onSetEraser` with `onSelect`.
|
||||
- adds `highlighterId` to config
|
||||
- adds keyboard navigation
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled.Aria as Aria
|
||||
import Accessibility.Styled.Role as Role
|
||||
import Css exposing (Color)
|
||||
import Html.Styled exposing (..)
|
||||
import Html.Styled.Attributes as Attributes exposing (css, id)
|
||||
import Html.Styled.Events exposing (onClick)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.FocusRing.V1 as FocusRing
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Html.Attributes.V2 exposing (nriDescription)
|
||||
import Nri.Ui.Html.V3 exposing (viewIf)
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
|
||||
|
||||
{-| View renders each marker and an eraser. This is exclusively used with an interactive Highlighter, whose id you should pass in when initializing the HighlighterToolbar.
|
||||
-}
|
||||
view :
|
||||
{ onSelect : Maybe tag -> msg
|
||||
, getNameAndColor : tag -> { extras | name : String, colorSolid : Color, colorLight : Color }
|
||||
, highlighterId : String
|
||||
}
|
||||
-> { model | currentTool : Maybe tag, tags : List tag }
|
||||
-> Html msg
|
||||
view config model =
|
||||
let
|
||||
viewTagWithConfig : tag -> Html msg
|
||||
viewTagWithConfig tag =
|
||||
viewTool config.onSelect (config.getNameAndColor tag) (Just tag) model
|
||||
in
|
||||
toolbar config.highlighterId
|
||||
(List.map viewTagWithConfig model.tags
|
||||
++ [ viewEraser config.onSelect model ]
|
||||
)
|
||||
|
||||
|
||||
toolbar : String -> List (Html msg) -> Html msg
|
||||
toolbar highlighterId =
|
||||
div
|
||||
[ nriDescription "tools"
|
||||
, Role.toolBar
|
||||
, Aria.label "Highlighter options"
|
||||
, Aria.controls [ highlighterId ]
|
||||
, css
|
||||
[ Css.displayFlex
|
||||
, Css.listStyle Css.none
|
||||
, Css.padding (Css.px 0)
|
||||
, Css.margin (Css.px 0)
|
||||
, Css.marginTop (Css.px 10)
|
||||
, Css.flexWrap Css.wrap
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
viewEraser :
|
||||
(Maybe tag -> msg)
|
||||
-> { model | currentTool : Maybe tag }
|
||||
-> Html msg
|
||||
viewEraser onSelect model =
|
||||
viewTool
|
||||
onSelect
|
||||
{ name = "Remove highlight"
|
||||
, colorLight = Colors.gray75
|
||||
, colorSolid = Colors.white
|
||||
}
|
||||
Nothing
|
||||
model
|
||||
|
||||
|
||||
viewTool :
|
||||
(Maybe tag -> msg)
|
||||
-> { extras | name : String, colorSolid : Color, colorLight : Color }
|
||||
-> Maybe tag
|
||||
-> { model | currentTool : Maybe tag }
|
||||
-> Html msg
|
||||
viewTool onSelect ({ name } as theme) tag model =
|
||||
let
|
||||
selected =
|
||||
model.currentTool == tag
|
||||
in
|
||||
label
|
||||
[ id ("tag-" ++ name)
|
||||
, css
|
||||
[ Css.cursor Css.pointer
|
||||
, Css.position Css.relative
|
||||
, Css.pseudoClass "focus-within" FocusRing.styles
|
||||
, Css.paddingBottom (Css.px 2)
|
||||
, Css.marginRight (Css.px 15)
|
||||
]
|
||||
]
|
||||
[ input
|
||||
[ Attributes.value name
|
||||
, Attributes.type_ "radio"
|
||||
, Attributes.name "highlighter-toolbar-tool"
|
||||
, Attributes.checked selected
|
||||
, onClick (onSelect tag)
|
||||
, css
|
||||
[ Css.cursor Css.pointer
|
||||
|
||||
-- position the radio input underneath the tool content
|
||||
, Css.position Css.absolute
|
||||
, Css.top (Css.px 4)
|
||||
, Css.left (Css.px 4)
|
||||
]
|
||||
, Attributes.class FocusRing.customClass
|
||||
]
|
||||
[]
|
||||
, toolContent name theme tag
|
||||
, viewIf (\() -> active theme) selected
|
||||
]
|
||||
|
||||
|
||||
active :
|
||||
{ extras | colorLight : Color }
|
||||
-> Html msg
|
||||
active palette_ =
|
||||
div
|
||||
[ nriDescription "active-tool"
|
||||
, css
|
||||
[ Css.width (Css.px 38)
|
||||
, Css.border3 (Css.px 2) Css.solid palette_.colorLight
|
||||
]
|
||||
]
|
||||
[]
|
||||
|
||||
|
||||
toolContent :
|
||||
String
|
||||
-> { extras | colorSolid : Color, colorLight : Color }
|
||||
-> Maybe tag
|
||||
-> Html msg
|
||||
toolContent name palette_ tool =
|
||||
span
|
||||
[ nriDescription "tool-content"
|
||||
, css
|
||||
[ Css.position Css.relative
|
||||
, Css.height (Css.pct 100)
|
||||
, Css.padding (Css.px 0)
|
||||
, Css.display Css.inlineFlex
|
||||
, Css.alignItems Css.center
|
||||
]
|
||||
]
|
||||
[ case tool of
|
||||
Just _ ->
|
||||
toolIcon
|
||||
{ background = palette_.colorSolid
|
||||
, border = palette_.colorSolid
|
||||
, icon = Svg.withColor Colors.white UiIcon.highlighter
|
||||
}
|
||||
|
||||
Nothing ->
|
||||
toolIcon
|
||||
{ background = palette_.colorSolid
|
||||
, border = Colors.gray75
|
||||
, icon = Svg.withColor Colors.gray20 UiIcon.eraser
|
||||
}
|
||||
, span
|
||||
[ nriDescription "tool-label"
|
||||
, css
|
||||
[ Css.color Colors.navy
|
||||
, Css.fontSize (Css.px 15)
|
||||
, Css.marginLeft (Css.px 5)
|
||||
, Css.fontWeight (Css.int 600)
|
||||
, Fonts.baseFont
|
||||
]
|
||||
]
|
||||
[ text name ]
|
||||
]
|
||||
|
||||
|
||||
toolIcon : { background : Color, border : Color, icon : Svg.Svg } -> Html msg
|
||||
toolIcon config =
|
||||
span
|
||||
[ css
|
||||
[ Css.backgroundColor config.background
|
||||
, Css.width (Css.px 38)
|
||||
, Css.height (Css.px 38)
|
||||
, Css.borderRadius (Css.pct 50)
|
||||
, Css.padding (Css.px 7)
|
||||
, Css.border3 (Css.px 1) Css.solid config.border
|
||||
]
|
||||
]
|
||||
[ Svg.toHtml config.icon
|
||||
]
|
@ -1,270 +1,115 @@
|
||||
module Spec.Nri.Ui.HighlighterToolbar exposing (..)
|
||||
|
||||
import Accessibility.Aria as Aria
|
||||
import Accessibility.Key as Key
|
||||
import Css exposing (Color)
|
||||
import Css
|
||||
import Expect
|
||||
import Html.Attributes as Attributes
|
||||
import Html.Styled as Html exposing (..)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.HighlighterToolbar.V2 as HighlighterToolbar
|
||||
import Nri.Ui.HighlighterToolbar.V3 as HighlighterToolbar
|
||||
import ProgramTest exposing (..)
|
||||
import Spec.KeyboardHelpers as KeyboardHelpers
|
||||
import Test exposing (..)
|
||||
import Test.Html.Event as Event
|
||||
import Test.Html.Query as Query
|
||||
import Test.Html.Selector as Selector
|
||||
import Test.Html.Selector as Selector exposing (Selector)
|
||||
|
||||
|
||||
spec : Test
|
||||
spec =
|
||||
describe "Nri.Ui.HighlighterToolbar.V2"
|
||||
[ describe "tool selection" selectionTests
|
||||
, describe "keyboard behavior" keyboardTests
|
||||
describe "Nri.Ui.HighlighterToolbar.V3"
|
||||
[ test "sets selection status on the active tool" <|
|
||||
\() ->
|
||||
program
|
||||
|> clickTool "Claim"
|
||||
|> ensureActiveToolIs "Claim"
|
||||
|> clickTool "Evidence"
|
||||
|> ensureActiveToolIs "Evidence"
|
||||
|> done
|
||||
]
|
||||
|
||||
|
||||
selectionTests : List Test
|
||||
selectionTests =
|
||||
[ test "sets aria-pressed to true on the active tool only" <|
|
||||
\() ->
|
||||
program
|
||||
|> clickTool "Claim"
|
||||
|> ensureActiveHasAriaPressedTrue "Claim"
|
||||
|> ensureNotActiveHaveAriaPressedFalse [ "Evidence", "Reasoning", "Remove highlight" ]
|
||||
|> clickTool "Evidence"
|
||||
|> ensureActiveHasAriaPressedTrue "Evidence"
|
||||
|> ensureNotActiveHaveAriaPressedFalse [ "Claim", "Reasoning", "Remove highlight" ]
|
||||
|> done
|
||||
, test "adds visual indicator to the active tool only" <|
|
||||
\() ->
|
||||
program
|
||||
|> clickTool "Claim"
|
||||
|> ensureActiveHasVisualIndicator
|
||||
|> ensureNotActiveDoNotHaveVisualIndicator
|
||||
|> done
|
||||
byLabel : String -> List Selector
|
||||
byLabel label =
|
||||
[ Selector.tag "label"
|
||||
, Selector.containing [ Selector.text label ]
|
||||
]
|
||||
|
||||
|
||||
keyboardTests : List Test
|
||||
keyboardTests =
|
||||
[ test "has a focusable tool" <|
|
||||
\() ->
|
||||
program
|
||||
|> ensureTabbable "Remove highlight"
|
||||
|> done
|
||||
, test "has only one tool included in the tab sequence" <|
|
||||
\() ->
|
||||
program
|
||||
|> ensureOnlyOneInTabSequence [ "Claim", "Evidence", "Reasoning", "Remove highlight" ]
|
||||
|> done
|
||||
, test "moves focus right on right arrow key. Should wrap focus on last element." <|
|
||||
\() ->
|
||||
program
|
||||
|> ensureTabbable "Remove highlight"
|
||||
|> rightArrow
|
||||
|> ensureTabbable "Claim"
|
||||
|> ensureOnlyOneInTabSequence [ "Claim", "Evidence", "Reasoning", "Remove highlight" ]
|
||||
|> rightArrow
|
||||
|> ensureTabbable "Evidence"
|
||||
|> rightArrow
|
||||
|> ensureTabbable "Reasoning"
|
||||
|> rightArrow
|
||||
|> ensureTabbable "Remove highlight"
|
||||
|> done
|
||||
, test "moves focus left on left arrow key. Should wrap focus on first element." <|
|
||||
\() ->
|
||||
program
|
||||
|> ensureTabbable "Remove highlight"
|
||||
|> leftArrow
|
||||
|> ensureTabbable "Reasoning"
|
||||
|> leftArrow
|
||||
|> ensureTabbable "Evidence"
|
||||
|> leftArrow
|
||||
|> ensureTabbable "Claim"
|
||||
|> leftArrow
|
||||
|> ensureTabbable "Remove highlight"
|
||||
|> ensureOnlyOneInTabSequence [ "Claim", "Evidence", "Reasoning", "Remove highlight" ]
|
||||
|> done
|
||||
]
|
||||
|
||||
|
||||
ensureTabbable : String -> TestContext -> TestContext
|
||||
ensureTabbable word testContext =
|
||||
testContext
|
||||
|> ensureView
|
||||
(Query.find [ Selector.attribute (Key.tabbable True) ]
|
||||
>> Query.has [ Selector.text word ]
|
||||
)
|
||||
|
||||
|
||||
ensureOnlyOneInTabSequence : List String -> TestContext -> TestContext
|
||||
ensureOnlyOneInTabSequence words testContext =
|
||||
testContext
|
||||
|> ensureView
|
||||
(Query.findAll [ Selector.attribute (Key.tabbable True) ]
|
||||
>> Query.count (Expect.equal 1)
|
||||
)
|
||||
|> ensureView
|
||||
(Query.findAll [ Selector.attribute (Key.tabbable False) ]
|
||||
>> Query.count (Expect.equal (List.length words - 1))
|
||||
)
|
||||
|
||||
|
||||
rightArrow : TestContext -> TestContext
|
||||
rightArrow =
|
||||
KeyboardHelpers.pressRightArrow { targetDetails = [] }
|
||||
[ Selector.attribute (Key.tabbable True) ]
|
||||
|
||||
|
||||
leftArrow : TestContext -> TestContext
|
||||
leftArrow =
|
||||
KeyboardHelpers.pressLeftArrow { targetDetails = [] }
|
||||
[ Selector.attribute (Key.tabbable True) ]
|
||||
activeToolVisualIndicator : List Selector
|
||||
activeToolVisualIndicator =
|
||||
[ Selector.attribute (Attributes.attribute "data-nri-description" "active-tool") ]
|
||||
|
||||
|
||||
clickTool : String -> ProgramTest model msg effect -> ProgramTest model msg effect
|
||||
clickTool label =
|
||||
ProgramTest.simulateDomEvent
|
||||
(Query.find
|
||||
[ Selector.tag "button"
|
||||
, Selector.containing [ Selector.text label ]
|
||||
]
|
||||
ProgramTest.within (Query.find (byLabel label))
|
||||
(ProgramTest.simulateDomEvent
|
||||
(Query.find [ Selector.tag "input" ])
|
||||
Event.click
|
||||
)
|
||||
Event.click
|
||||
|
||||
|
||||
ensureActiveHasAriaPressedTrue : String -> TestContext -> TestContext
|
||||
ensureActiveHasAriaPressedTrue label testContext =
|
||||
ensureActiveToolIs : String -> ProgramTest model msg effect -> ProgramTest model msg effect
|
||||
ensureActiveToolIs label testContext =
|
||||
testContext
|
||||
|> ensureView
|
||||
(Query.find [ Selector.attribute (Aria.pressed (Just True)) ]
|
||||
>> Query.has [ Selector.text label ]
|
||||
|> ProgramTest.within (Query.find (byLabel label))
|
||||
-- has the attribute showing the radio as checked
|
||||
(ProgramTest.ensureViewHas [ Selector.attribute (Attributes.checked True) ]
|
||||
-- has a visual indicator of selection
|
||||
>> ProgramTest.ensureViewHas activeToolVisualIndicator
|
||||
)
|
||||
|> ProgramTest.ensureView
|
||||
-- has only 1 checked radio
|
||||
(Query.findAll [ Selector.attribute (Attributes.checked True) ]
|
||||
>> Query.count (Expect.equal 1)
|
||||
)
|
||||
|> ProgramTest.ensureView
|
||||
-- has only 1 visual indicator of selection
|
||||
(Query.findAll activeToolVisualIndicator
|
||||
>> Query.count (Expect.equal 1)
|
||||
)
|
||||
|
||||
|
||||
ensureNotActiveHaveAriaPressedFalse : List String -> TestContext -> TestContext
|
||||
ensureNotActiveHaveAriaPressedFalse labels testContext =
|
||||
testContext
|
||||
|> ensureView
|
||||
(Query.findAll [ Selector.attribute (Aria.pressed (Just False)) ]
|
||||
>> Expect.all (List.indexedMap (\i label -> Query.index i >> Query.has [ Selector.text label ]) labels)
|
||||
)
|
||||
|
||||
|
||||
ensureActiveHasVisualIndicator : TestContext -> TestContext
|
||||
ensureActiveHasVisualIndicator testContext =
|
||||
testContext
|
||||
|> ensureView
|
||||
(Query.find
|
||||
[ Selector.attribute (Aria.pressed (Just True)) ]
|
||||
>> Query.has [ Selector.attribute (Attributes.attribute "data-nri-description" "active-tool") ]
|
||||
)
|
||||
|
||||
|
||||
ensureNotActiveDoNotHaveVisualIndicator : TestContext -> TestContext
|
||||
ensureNotActiveDoNotHaveVisualIndicator testContext =
|
||||
testContext
|
||||
|> ensureView
|
||||
(Query.findAll
|
||||
[ Selector.attribute (Aria.pressed (Just False)) ]
|
||||
>> Query.each
|
||||
(Query.hasNot
|
||||
[ Selector.attribute (Attributes.attribute "data-nri-description" "active-tool") ]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
type Tag
|
||||
= Claim
|
||||
| Evidence
|
||||
| Reasoning
|
||||
type alias Tag =
|
||||
{ name : String
|
||||
, colorSolid : Css.Color
|
||||
, colorLight : Css.Color
|
||||
}
|
||||
|
||||
|
||||
tags : List Tag
|
||||
tags =
|
||||
[ Claim, Evidence, Reasoning ]
|
||||
[ { name = "Claim"
|
||||
, colorSolid = Colors.mustard
|
||||
, colorLight = Colors.highlightYellow
|
||||
}
|
||||
, { name = "Evidence"
|
||||
, colorSolid = Colors.magenta
|
||||
, colorLight = Colors.highlightMagenta
|
||||
}
|
||||
, { name = "Reasoning"
|
||||
, colorSolid = Colors.cyan
|
||||
, colorLight = Colors.highlightCyan
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
getName : Tag -> String
|
||||
getName tag =
|
||||
case tag of
|
||||
Claim ->
|
||||
"Claim"
|
||||
|
||||
Evidence ->
|
||||
"Evidence"
|
||||
|
||||
Reasoning ->
|
||||
"Reasoning"
|
||||
|
||||
|
||||
getColor : Tag -> { colorSolid : Color, colorLight : Color }
|
||||
getColor tag =
|
||||
case tag of
|
||||
Claim ->
|
||||
{ colorSolid = Colors.mustard
|
||||
, colorLight = Colors.highlightYellow
|
||||
}
|
||||
|
||||
Evidence ->
|
||||
{ colorSolid = Colors.magenta
|
||||
, colorLight = Colors.highlightMagenta
|
||||
}
|
||||
|
||||
Reasoning ->
|
||||
{ colorSolid = Colors.cyan
|
||||
, colorLight = Colors.highlightCyan
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias State =
|
||||
{ currentTool : Maybe Tag
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
init : State
|
||||
init =
|
||||
{ currentTool = Nothing }
|
||||
|
||||
|
||||
{-| -}
|
||||
type Msg
|
||||
= FocusAndSelectTag { select : Maybe Tag, focus : Maybe String }
|
||||
|
||||
|
||||
{-| -}
|
||||
update : Msg -> State -> State
|
||||
update msg state =
|
||||
case msg of
|
||||
FocusAndSelectTag { select } ->
|
||||
{ state | currentTool = select }
|
||||
|
||||
|
||||
view : State -> Html Msg
|
||||
view : Maybe Tag -> Html (Maybe Tag)
|
||||
view model =
|
||||
HighlighterToolbar.view
|
||||
{ focusAndSelect = FocusAndSelectTag
|
||||
, getColor = getColor
|
||||
, getName = getName
|
||||
{ onSelect = identity
|
||||
, getNameAndColor = identity
|
||||
, highlighterId = "highlighter"
|
||||
}
|
||||
{ currentTool = model.currentTool
|
||||
{ currentTool = model
|
||||
, tags = tags
|
||||
}
|
||||
|
||||
|
||||
type alias TestContext =
|
||||
ProgramTest State Msg ()
|
||||
|
||||
|
||||
program : TestContext
|
||||
program : ProgramTest (Maybe Tag) (Maybe Tag) ()
|
||||
program =
|
||||
ProgramTest.createSandbox
|
||||
{ init = init
|
||||
, update = update
|
||||
{ init = Nothing
|
||||
, update = \new _ -> new
|
||||
, view = view >> Html.toUnstyled
|
||||
}
|
||||
|> ProgramTest.start ()
|
||||
|
@ -37,6 +37,7 @@
|
||||
"Nri.Ui.HighlighterTool.V1",
|
||||
"Nri.Ui.HighlighterToolbar.V1",
|
||||
"Nri.Ui.HighlighterToolbar.V2",
|
||||
"Nri.Ui.HighlighterToolbar.V3",
|
||||
"Nri.Ui.Html.Attributes.V2",
|
||||
"Nri.Ui.Html.V3",
|
||||
"Nri.Ui.InputStyles.V4",
|
||||
|
Loading…
Reference in New Issue
Block a user