Begin converting to more typical list-style implementation uner the hood

This commit is contained in:
Tessa Kelly 2022-04-18 18:01:51 -07:00
parent 13182063ad
commit 8a0267136b
2 changed files with 98 additions and 67 deletions

View File

@ -1,4 +1,9 @@
module Nri.Ui.Switch.V2 exposing (view, Attribute, onSwitch, disabled, id, label, custom) module Nri.Ui.Switch.V2 exposing
( view, label
, Attribute
, containerCss, labelCss, custom, nriDescription, id, testId
, onSwitch, disabled, enabled
)
{-| {-|
@ -6,21 +11,31 @@ module Nri.Ui.Switch.V2 exposing (view, Attribute, onSwitch, disabled, id, label
# Changes from V1: # Changes from V1:
- Fixes invalid ARIA use, [conformance requirements](https://www.w3.org/TR/html-aria/#docconformance) - Fixes invalid ARIA use, [conformance requirements](https://www.w3.org/TR/html-aria/#docconformance)
- labels should only support strings (this is the only way they're actually used in practice)
- extends API to be more consistent with other form/control components
@docs view, Attribute, onSwitch, disabled, id, label, custom @docs view, label
### Attributes
@docs Attribute
@docs containerCss, labelCss, custom, nriDescription, id, testId
@docs onSwitch, disabled, enabled
-} -}
import Accessibility.Styled as Html exposing (Html) import Accessibility.Styled as Html exposing (Html)
import Accessibility.Styled.Aria as Aria import Accessibility.Styled.Aria as Aria
import Accessibility.Styled.Widget as Widget import Accessibility.Styled.Widget as Widget
import Css import Css exposing (Style)
import Css.Global as Global import Css.Global as Global
import Css.Media import Css.Media
import Html.Styled as WildWildHtml import Html.Styled as WildWildHtml
import Html.Styled.Attributes as Attributes import Html.Styled.Attributes as Attributes
import Html.Styled.Events as Events import Html.Styled.Events as Events
import Nri.Ui.Colors.V1 as Colors import Nri.Ui.Colors.V1 as Colors
import Nri.Ui.Html.Attributes.V2 as Extra
import Nri.Ui.Svg.V1 exposing (Svg) import Nri.Ui.Svg.V1 exposing (Svg)
import Svg.Styled as Svg import Svg.Styled as Svg
import Svg.Styled.Attributes as SvgAttributes import Svg.Styled.Attributes as SvgAttributes
@ -28,18 +43,14 @@ import Svg.Styled.Attributes as SvgAttributes
{-| -} {-| -}
type Attribute msg type Attribute msg
= OnSwitch (Bool -> msg) = Attribute (Config msg -> Config msg)
| Id String
| Label (Html msg)
| Disabled
| Custom (List (Html.Attribute Never))
{-| Specify what happens when the switch is toggled. {-| Specify what happens when the switch is toggled.
-} -}
onSwitch : (Bool -> msg) -> Attribute msg onSwitch : (Bool -> msg) -> Attribute msg
onSwitch = onSwitch onSwitch_ =
OnSwitch Attribute <| \config -> { config | onSwitch = Just onSwitch_ }
{-| Explicitly specify that you want this switch to be disabled. If you don't {-| Explicitly specify that you want this switch to be disabled. If you don't
@ -48,7 +59,13 @@ to resort to `filterMap` or similar to build a clean list of attributes.
-} -}
disabled : Attribute msg disabled : Attribute msg
disabled = disabled =
Disabled Attribute <| \config -> { config | isDisabled = True }
{-| -}
enabled : Attribute msg
enabled =
Attribute <| \config -> { config | isDisabled = False }
{-| Set the HTML ID of the switch toggle. If you have only one on the page, {-| Set the HTML ID of the switch toggle. If you have only one on the page,
@ -56,31 +73,64 @@ you don't need to set this, but you should definitely set it if you have
more than one. more than one.
-} -}
id : String -> Attribute msg id : String -> Attribute msg
id = id id_ =
Id Attribute <| \config -> { config | id = id_ }
{-| Add labeling text to the switch. This text should be descriptive and {-| Add labeling text to the switch. This text should be descriptive and
able to be displayed inline. It should _not_ be interactive (if it were able to be displayed inline.
ergonomic to make this argument `Html Never`, we would!)
-} -}
label : Html msg -> Attribute msg label : String -> Attribute msg
label = label label_ =
Label Attribute <| \config -> { config | label = label_ }
{-| Pass custom attributes through to be attached to the underlying input. {-| Pass custom attributes through to be attached to the underlying input.
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 `containerCss` or `labelCss`.
-} -}
custom : List (Html.Attribute Never) -> Attribute msg custom : List (Html.Attribute Never) -> Attribute msg
custom = custom custom_ =
Custom Attribute <| \config -> { config | custom = config.custom ++ custom_ }
{-| -}
nriDescription : String -> Attribute msg
nriDescription description =
custom [ Extra.nriDescription description ]
{-| -}
testId : String -> Attribute msg
testId id_ =
custom [ Extra.testId id_ ]
{-| Adds CSS to the Switch container.
-}
containerCss : List Css.Style -> Attribute msg
containerCss styles =
Attribute <| \config -> { config | containerCss = config.containerCss ++ styles }
{-| Adds CSS to the `label` element.
-}
labelCss : List Css.Style -> Attribute msg
labelCss styles =
Attribute <| \config -> { config | labelCss = config.labelCss ++ styles }
type alias Config msg = type alias Config msg =
{ onSwitch : Maybe (Bool -> msg) { onSwitch : Maybe (Bool -> msg)
, id : String , id : String
, label : Maybe (Html msg) , label : String
, attributes : List (Html.Attribute Never) , containerCss : List Style
, labelCss : List Style
, isDisabled : Bool
, custom : List (Html.Attribute Never)
} }
@ -88,30 +138,14 @@ defaultConfig : Config msg
defaultConfig = defaultConfig =
{ onSwitch = Nothing { onSwitch = Nothing
, id = "nri-ui-switch-with-default-id" , id = "nri-ui-switch-with-default-id"
, label = Nothing , label = ""
, attributes = [] , containerCss = []
, labelCss = []
, isDisabled = False
, custom = []
} }
customize : Attribute msg -> Config msg -> Config msg
customize attr config =
case attr of
OnSwitch onSwitch_ ->
{ config | onSwitch = Just onSwitch_ }
Disabled ->
{ config | onSwitch = Nothing }
Id id_ ->
{ config | id = id_ }
Label label_ ->
{ config | label = Just label_ }
Custom custom_ ->
{ config | attributes = custom_ }
{-| Render a switch. The boolean here indicates whether the switch is on {-| Render a switch. The boolean here indicates whether the switch is on
or not. or not.
-} -}
@ -119,7 +153,7 @@ view : List (Attribute msg) -> Bool -> Html msg
view attrs isOn = view attrs isOn =
let let
config = config =
List.foldl customize defaultConfig attrs List.foldl (\(Attribute update) -> update) defaultConfig attrs
in in
WildWildHtml.label WildWildHtml.label
[ Attributes.id (config.id ++ "-container") [ Attributes.id (config.id ++ "-container")
@ -151,7 +185,7 @@ view attrs isOn =
{ id = config.id { id = config.id
, onCheck = config.onSwitch , onCheck = config.onSwitch
, checked = isOn , checked = isOn
, attributes = config.attributes , custom = config.custom
} }
, Nri.Ui.Svg.V1.toHtml , Nri.Ui.Svg.V1.toHtml
(viewSwitch (viewSwitch
@ -160,20 +194,17 @@ view attrs isOn =
, enabled = config.onSwitch /= Nothing , enabled = config.onSwitch /= Nothing
} }
) )
, case config.label of , -- TODO: This element should literally be a label.
Just label_ -> -- The `for` attribute is meaningless for a `span`.
Html.span Html.span
[ Attributes.css [ Attributes.css
[ Css.fontWeight (Css.int 600) [ Css.fontWeight (Css.int 600)
, Css.color Colors.navy , Css.color Colors.navy
, Css.paddingLeft (Css.px 5) , Css.paddingLeft (Css.px 5)
] ]
, Attributes.for config.id , Attributes.for config.id
] ]
[ label_ ] [ Html.text config.label ]
Nothing ->
Html.text ""
] ]
@ -181,7 +212,7 @@ viewCheckbox :
{ id : String { id : String
, onCheck : Maybe (Bool -> msg) , onCheck : Maybe (Bool -> msg)
, checked : Bool , checked : Bool
, attributes : List (Html.Attribute Never) , custom : List (Html.Attribute Never)
} }
-> Html msg -> Html msg
viewCheckbox config = viewCheckbox config =
@ -202,7 +233,7 @@ viewCheckbox config =
Nothing -> Nothing ->
Widget.disabled True Widget.disabled True
] ]
++ List.map (Attributes.map never) config.attributes ++ List.map (Attributes.map never) config.custom
) )

View File

@ -33,12 +33,12 @@ example =
, subscriptions = \_ -> Sub.none , subscriptions = \_ -> Sub.none
, preview = , preview =
[ Switch.view [ Switch.view
[ Switch.label (Html.text "Toggle On") [ Switch.label "Toggle On"
, Switch.custom [ Key.tabbable False ] , Switch.custom [ Key.tabbable False ]
] ]
False False
, Switch.view , Switch.view
[ Switch.label (Html.text "Toggle Off") [ Switch.label "Toggle Off"
, Switch.custom [ Key.tabbable False ] , Switch.custom [ Key.tabbable False ]
] ]
True True
@ -51,10 +51,10 @@ example =
, Switch.id "switch-interactive" , Switch.id "switch-interactive"
, Switch.label , Switch.label
(if interactiveIsOn then (if interactiveIsOn then
Html.text "On" "On"
else else
Html.text "Off" "Off"
) )
] ]
interactiveIsOn interactiveIsOn
@ -62,14 +62,14 @@ example =
, Switch.view , Switch.view
[ Switch.disabled [ Switch.disabled
, Switch.id "switch-disabled-on" , Switch.id "switch-disabled-on"
, Switch.label (Html.text "Permanently on") , Switch.label "Permanently on"
] ]
True True
, Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Disabled (Off)" ] , Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Disabled (Off)" ]
, Switch.view , Switch.view
[ Switch.disabled [ Switch.disabled
, Switch.id "switch-disabled-off" , Switch.id "switch-disabled-off"
, Switch.label (Html.text "Permanently off") , Switch.label "Permanently off"
] ]
False False
] ]