From 082a23096f55148eaaa3fb802e8c87e4c90171d7 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 17:38:22 -0700 Subject: [PATCH 01/17] Make the Switch test fail --- script/puppeteer-tests.js | 1 - 1 file changed, 1 deletion(-) diff --git a/script/puppeteer-tests.js b/script/puppeteer-tests.js index 223d4a69..22d3e1e1 100644 --- a/script/puppeteer-tests.js +++ b/script/puppeteer-tests.js @@ -71,7 +71,6 @@ describe('UI tests', function () { const skippedRules = { 'RadioButton': ['duplicate-id'], - 'Switch': ['aria-allowed-attr'], } const specialProcessing = { From f720eef94caa0435e3c8aec71701ee16a034a174 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 17:38:49 -0700 Subject: [PATCH 02/17] cop V1 to V2 --- src/Nri/Ui/Switch/V2.elm | 350 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 src/Nri/Ui/Switch/V2.elm diff --git a/src/Nri/Ui/Switch/V2.elm b/src/Nri/Ui/Switch/V2.elm new file mode 100644 index 00000000..08f2f14c --- /dev/null +++ b/src/Nri/Ui/Switch/V2.elm @@ -0,0 +1,350 @@ +module Nri.Ui.Switch.V1 exposing (view, Attribute, onSwitch, disabled, id, label, custom) + +{-| + +@docs view, Attribute, onSwitch, disabled, id, label, custom + +-} + +import Accessibility.Styled as Html exposing (Html) +import Accessibility.Styled.Aria as Aria +import Accessibility.Styled.Widget as Widget +import Css +import Css.Global as Global +import Css.Media +import Html.Styled as WildWildHtml +import Html.Styled.Attributes as Attributes +import Html.Styled.Events as Events +import Nri.Ui.Colors.V1 as Colors +import Nri.Ui.Svg.V1 exposing (Svg) +import Svg.Styled as Svg +import Svg.Styled.Attributes as SvgAttributes + + +{-| -} +type Attribute msg + = OnSwitch (Bool -> msg) + | Id String + | Label (Html msg) + | Disabled + | Custom (List (Html.Attribute Never)) + + +{-| Specify what happens when the switch is toggled. +-} +onSwitch : (Bool -> msg) -> Attribute msg +onSwitch = + OnSwitch + + +{-| Explicitly specify that you want this switch to be disabled. If you don't +specify `onSwitch`, this is the default, but it's provided so you don't have +to resort to `filterMap` or similar to build a clean list of attributes. +-} +disabled : Attribute msg +disabled = + Disabled + + +{-| Set the HTML ID of the switch toggle. If you have only one on the page, +you don't need to set this, but you should definitely set it if you have +more than one. +-} +id : String -> Attribute msg +id = + Id + + +{-| 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 +ergonomic to make this argument `Html Never`, we would!) +-} +label : Html msg -> Attribute msg +label = + Label + + +{-| Pass custom attributes through to be attached to the underlying input. +-} +custom : List (Html.Attribute Never) -> Attribute msg +custom = + Custom + + +type alias Config msg = + { onSwitch : Maybe (Bool -> msg) + , id : String + , label : Maybe (Html msg) + , attributes : List (Html.Attribute Never) + } + + +defaultConfig : Config msg +defaultConfig = + { onSwitch = Nothing + , id = "nri-ui-switch-with-default-id" + , label = Nothing + , attributes = [] + } + + +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 +or not. +-} +view : List (Attribute msg) -> Bool -> Html msg +view attrs isOn = + let + config = + List.foldl customize defaultConfig attrs + in + WildWildHtml.label + [ Attributes.id (config.id ++ "-container") + , Attributes.css + [ Css.display Css.inlineFlex + , Css.alignItems Css.center + , Css.position Css.relative + , Css.pseudoClass "focus-within" + [ Global.descendants + [ Global.class "switch-slider" + [ -- azure, but can't use the Color type here + Css.property "stroke" "#146AFF" + , Css.property "stroke-width" "3px" + ] + ] + ] + , Css.cursor + (if config.onSwitch /= Nothing then + Css.pointer + + else + Css.notAllowed + ) + ] + , Aria.controls config.id + , Widget.checked (Just isOn) + ] + [ viewCheckbox + { id = config.id + , onCheck = config.onSwitch + , checked = isOn + , attributes = config.attributes + } + , Nri.Ui.Svg.V1.toHtml + (viewSwitch + { id = config.id + , isOn = isOn + , enabled = config.onSwitch /= Nothing + } + ) + , case config.label of + Just label_ -> + Html.span + [ Attributes.css + [ Css.fontWeight (Css.int 600) + , Css.color Colors.navy + , Css.paddingLeft (Css.px 5) + ] + , Attributes.for config.id + ] + [ label_ ] + + Nothing -> + Html.text "" + ] + + +viewCheckbox : + { id : String + , onCheck : Maybe (Bool -> msg) + , checked : Bool + , attributes : List (Html.Attribute Never) + } + -> Html msg +viewCheckbox config = + Html.checkbox config.id + (Just config.checked) + ([ Attributes.id config.id + , Attributes.css + [ Css.position Css.absolute + , Css.top (Css.px 10) + , Css.left (Css.px 10) + , Css.zIndex (Css.int 0) + , Css.opacity (Css.num 0) + ] + , case config.onCheck of + Just onCheck -> + Events.onCheck onCheck + + Nothing -> + Widget.disabled True + ] + ++ List.map (Attributes.map never) config.attributes + ) + + +viewSwitch : + { id : String + , isOn : Bool + , enabled : Bool + } + -> Svg +viewSwitch config = + let + shadowFilterId = + config.id ++ "-shadow-filter" + + shadowBoxId = + config.id ++ "-shadow-box" + in + Svg.svg + [ SvgAttributes.width "43" + , SvgAttributes.height "32" + , SvgAttributes.viewBox "0 0 43 32" + , SvgAttributes.css + [ Css.zIndex (Css.int 1) + , if config.enabled then + Css.opacity (Css.num 1) + + else + Css.opacity (Css.num 0.4) + ] + ] + [ Svg.defs [] + [ Svg.filter + [ SvgAttributes.id shadowFilterId + , SvgAttributes.width "105%" + , SvgAttributes.height "106.7%" + , SvgAttributes.x "-2.5%" + , SvgAttributes.y "-3.3%" + , SvgAttributes.filterUnits "objectBoundingBox" + ] + [ Svg.feOffset + [ SvgAttributes.dy "2" + , SvgAttributes.in_ "SourceAlpha" + , SvgAttributes.result "shadowOffsetInner1" + ] + [] + , Svg.feComposite + [ SvgAttributes.in_ "shadowOffsetInner1" + , SvgAttributes.in2 "SourceAlpha" + , SvgAttributes.k2 "-1" + , SvgAttributes.k3 "1" + , SvgAttributes.operator "arithmetic" + , SvgAttributes.result "shadowInnerInner1" + ] + [] + , Svg.feColorMatrix + [ SvgAttributes.in_ "shadowInnerInner1" + , SvgAttributes.values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" + ] + [] + ] + , Svg.rect + [ SvgAttributes.id shadowBoxId + , SvgAttributes.width "40" + , SvgAttributes.height "30" + , SvgAttributes.x "0" + , SvgAttributes.y "0" + , SvgAttributes.rx "15" + ] + [] + ] + , Svg.g + [ SvgAttributes.fill "none" + , SvgAttributes.fillRule "even-odd" + , SvgAttributes.transform "translate(1, 1)" + ] + [ Svg.g [] + [ Svg.use + [ SvgAttributes.xlinkHref ("#" ++ shadowBoxId) + , SvgAttributes.css + [ if config.isOn then + Css.fill Colors.glacier + + else + Css.fill Colors.gray92 + , transition "fill 0.2s" + ] + ] + [] + , Svg.use + [ SvgAttributes.xlinkHref ("#" ++ shadowBoxId) + , SvgAttributes.fill "#000" + , SvgAttributes.filter ("url(#" ++ shadowFilterId ++ ")") + ] + [] + ] + , Svg.g + [ SvgAttributes.css + [ if config.isOn then + Css.transform (Css.translateX (Css.px 11)) + + else + Css.transform (Css.translateX (Css.px 0)) + , transition "transform 0.2s ease-in-out" + ] + ] + [ Svg.circle + [ SvgAttributes.cx "15" + , SvgAttributes.cy "15" + , SvgAttributes.r "14.5" + , SvgAttributes.fill "#FFF" + , SvgAttributes.css + [ if config.isOn then + -- azure, but can't use the Color type here + Css.property "stroke" "#146AFF" + + else + -- gray75, but can't use the Color type here + Css.property "stroke" "#BFBFBF" + , transition "stroke 0.1s" + ] + , SvgAttributes.class "switch-slider" + ] + [] + , Svg.path + [ SvgAttributes.strokeLinecap "round" + , SvgAttributes.strokeLinejoin "round" + , SvgAttributes.strokeWidth "3" + , SvgAttributes.d "M8 15.865L12.323 20 21.554 10" + , SvgAttributes.css + [ if config.isOn then + -- azure, but can't use the Color type here + Css.property "stroke" "#146AFF" + + else + Css.property "stroke" "rgba(255,255,255,0)" + , transition "stroke 0.2s" + ] + ] + [] + ] + ] + ] + |> Nri.Ui.Svg.V1.fromHtml + + +transition : String -> Css.Style +transition transitionRules = + Css.Media.withMediaQuery + [ "(prefers-reduced-motion: no-preference)" ] + [ Css.property "transition" transitionRules ] From 13182063ad232e0ae85bed3d619586480dd30181 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 17:40:39 -0700 Subject: [PATCH 03/17] Expose and use unmodified Switch --- deprecated-modules.csv | 1 + elm.json | 1 + forbidden-imports.toml | 3 +++ src/Nri/Ui/Switch/V2.elm | 7 ++++++- styleguide-app/Examples/Switch.elm | 2 +- tests/elm-verify-examples.json | 1 + 6 files changed, 13 insertions(+), 2 deletions(-) diff --git a/deprecated-modules.csv b/deprecated-modules.csv index b81497f8..f2553508 100644 --- a/deprecated-modules.csv +++ b/deprecated-modules.csv @@ -7,6 +7,7 @@ Nri.Ui.RadioButton.V2,upgrade to V4 Nri.Ui.RadioButton.V3,upgrade to V4 Nri.Ui.SideNav.V1,upgrade to V3 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 diff --git a/elm.json b/elm.json index 8c8a007e..b8ac22d9 100644 --- a/elm.json +++ b/elm.json @@ -61,6 +61,7 @@ "Nri.Ui.Sprite.V1", "Nri.Ui.Svg.V1", "Nri.Ui.Switch.V1", + "Nri.Ui.Switch.V2", "Nri.Ui.Table.V4", "Nri.Ui.Table.V5", "Nri.Ui.Tabs.V6", diff --git a/forbidden-imports.toml b/forbidden-imports.toml index d34da00f..14c840fc 100644 --- a/forbidden-imports.toml +++ b/forbidden-imports.toml @@ -114,6 +114,9 @@ hint = 'upgrade to V3' [forbidden."Nri.Ui.SideNav.V2"] hint = 'upgrade to V3' +[forbidden."Nri.Ui.Switch.V1"] +hint = 'upgrade to V2' + [forbidden."Nri.Ui.Table.V4"] hint = 'upgrade to V5' diff --git a/src/Nri/Ui/Switch/V2.elm b/src/Nri/Ui/Switch/V2.elm index 08f2f14c..519ac956 100644 --- a/src/Nri/Ui/Switch/V2.elm +++ b/src/Nri/Ui/Switch/V2.elm @@ -1,7 +1,12 @@ -module Nri.Ui.Switch.V1 exposing (view, Attribute, onSwitch, disabled, id, label, custom) +module Nri.Ui.Switch.V2 exposing (view, Attribute, onSwitch, disabled, id, label, custom) {-| + +# Changes from V1: + + - Fixes invalid ARIA use, [conformance requirements](https://www.w3.org/TR/html-aria/#docconformance) + @docs view, Attribute, onSwitch, disabled, id, label, custom -} diff --git a/styleguide-app/Examples/Switch.elm b/styleguide-app/Examples/Switch.elm index 9e870fb7..d53101b6 100644 --- a/styleguide-app/Examples/Switch.elm +++ b/styleguide-app/Examples/Switch.elm @@ -11,7 +11,7 @@ import Category import Example exposing (Example) import Html.Styled as Html import Nri.Ui.Heading.V2 as Heading -import Nri.Ui.Switch.V1 as Switch +import Nri.Ui.Switch.V2 as Switch {-| -} diff --git a/tests/elm-verify-examples.json b/tests/elm-verify-examples.json index d289e0b3..e4b8bea7 100644 --- a/tests/elm-verify-examples.json +++ b/tests/elm-verify-examples.json @@ -57,6 +57,7 @@ "Nri.Ui.Sprite.V1", "Nri.Ui.Svg.V1", "Nri.Ui.Switch.V1", + "Nri.Ui.Switch.V2", "Nri.Ui.Table.V4", "Nri.Ui.Table.V5", "Nri.Ui.Tabs.V6", From 8a0267136b2c5386edabcf59004c5695f9c7461a Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 18:01:51 -0700 Subject: [PATCH 04/17] Begin converting to more typical list-style implementation uner the hood --- src/Nri/Ui/Switch/V2.elm | 153 +++++++++++++++++------------ styleguide-app/Examples/Switch.elm | 12 +-- 2 files changed, 98 insertions(+), 67 deletions(-) diff --git a/src/Nri/Ui/Switch/V2.elm b/src/Nri/Ui/Switch/V2.elm index 519ac956..a9e42c26 100644 --- a/src/Nri/Ui/Switch/V2.elm +++ b/src/Nri/Ui/Switch/V2.elm @@ -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: - 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.Aria as Aria import Accessibility.Styled.Widget as Widget -import Css +import Css exposing (Style) import Css.Global as Global import Css.Media import Html.Styled as WildWildHtml import Html.Styled.Attributes as Attributes import Html.Styled.Events as Events import Nri.Ui.Colors.V1 as Colors +import Nri.Ui.Html.Attributes.V2 as Extra import Nri.Ui.Svg.V1 exposing (Svg) import Svg.Styled as Svg import Svg.Styled.Attributes as SvgAttributes @@ -28,18 +43,14 @@ import Svg.Styled.Attributes as SvgAttributes {-| -} type Attribute msg - = OnSwitch (Bool -> msg) - | Id String - | Label (Html msg) - | Disabled - | Custom (List (Html.Attribute Never)) + = Attribute (Config msg -> Config msg) {-| Specify what happens when the switch is toggled. -} 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 @@ -48,7 +59,13 @@ to resort to `filterMap` or similar to build a clean list of attributes. -} disabled : Attribute msg 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, @@ -56,31 +73,64 @@ you don't need to set this, but you should definitely set it if you have more than one. -} 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 -able to be displayed inline. It should _not_ be interactive (if it were -ergonomic to make this argument `Html Never`, we would!) +able to be displayed inline. -} -label : Html msg -> Attribute msg -label = - Label +label : String -> Attribute msg +label label_ = + Attribute <| \config -> { config | label = label_ } {-| 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 = - 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 = { onSwitch : Maybe (Bool -> msg) , id : String - , label : Maybe (Html msg) - , attributes : List (Html.Attribute Never) + , label : String + , containerCss : List Style + , labelCss : List Style + , isDisabled : Bool + , custom : List (Html.Attribute Never) } @@ -88,30 +138,14 @@ defaultConfig : Config msg defaultConfig = { onSwitch = Nothing , id = "nri-ui-switch-with-default-id" - , label = Nothing - , attributes = [] + , label = "" + , 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 or not. -} @@ -119,7 +153,7 @@ view : List (Attribute msg) -> Bool -> Html msg view attrs isOn = let config = - List.foldl customize defaultConfig attrs + List.foldl (\(Attribute update) -> update) defaultConfig attrs in WildWildHtml.label [ Attributes.id (config.id ++ "-container") @@ -151,7 +185,7 @@ view attrs isOn = { id = config.id , onCheck = config.onSwitch , checked = isOn - , attributes = config.attributes + , custom = config.custom } , Nri.Ui.Svg.V1.toHtml (viewSwitch @@ -160,20 +194,17 @@ view attrs isOn = , enabled = config.onSwitch /= Nothing } ) - , case config.label of - Just label_ -> - Html.span - [ Attributes.css - [ Css.fontWeight (Css.int 600) - , Css.color Colors.navy - , Css.paddingLeft (Css.px 5) - ] - , Attributes.for config.id - ] - [ label_ ] - - Nothing -> - Html.text "" + , -- TODO: This element should literally be a label. + -- The `for` attribute is meaningless for a `span`. + Html.span + [ Attributes.css + [ Css.fontWeight (Css.int 600) + , Css.color Colors.navy + , Css.paddingLeft (Css.px 5) + ] + , Attributes.for config.id + ] + [ Html.text config.label ] ] @@ -181,7 +212,7 @@ viewCheckbox : { id : String , onCheck : Maybe (Bool -> msg) , checked : Bool - , attributes : List (Html.Attribute Never) + , custom : List (Html.Attribute Never) } -> Html msg viewCheckbox config = @@ -202,7 +233,7 @@ viewCheckbox config = Nothing -> Widget.disabled True ] - ++ List.map (Attributes.map never) config.attributes + ++ List.map (Attributes.map never) config.custom ) diff --git a/styleguide-app/Examples/Switch.elm b/styleguide-app/Examples/Switch.elm index d53101b6..1c554b09 100644 --- a/styleguide-app/Examples/Switch.elm +++ b/styleguide-app/Examples/Switch.elm @@ -33,12 +33,12 @@ example = , subscriptions = \_ -> Sub.none , preview = [ Switch.view - [ Switch.label (Html.text "Toggle On") + [ Switch.label "Toggle On" , Switch.custom [ Key.tabbable False ] ] False , Switch.view - [ Switch.label (Html.text "Toggle Off") + [ Switch.label "Toggle Off" , Switch.custom [ Key.tabbable False ] ] True @@ -51,10 +51,10 @@ example = , Switch.id "switch-interactive" , Switch.label (if interactiveIsOn then - Html.text "On" + "On" else - Html.text "Off" + "Off" ) ] interactiveIsOn @@ -62,14 +62,14 @@ example = , Switch.view [ Switch.disabled , Switch.id "switch-disabled-on" - , Switch.label (Html.text "Permanently on") + , Switch.label "Permanently on" ] True , Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Disabled (Off)" ] , Switch.view [ Switch.disabled , Switch.id "switch-disabled-off" - , Switch.label (Html.text "Permanently off") + , Switch.label "Permanently off" ] False ] From fe5cbf65bcbe87bd2ae0ecdc4e953b76c19d90d6 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 18:05:57 -0700 Subject: [PATCH 05/17] Use Azure as expected --- src/Nri/Ui/Colors/Extra.elm | 8 ++++++++ src/Nri/Ui/SortableTable/V2.elm | 8 +------- src/Nri/Ui/Switch/V2.elm | 5 +++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Nri/Ui/Colors/Extra.elm b/src/Nri/Ui/Colors/Extra.elm index 8f9dbda1..ca296ee6 100644 --- a/src/Nri/Ui/Colors/Extra.elm +++ b/src/Nri/Ui/Colors/Extra.elm @@ -1,6 +1,7 @@ module Nri.Ui.Colors.Extra exposing ( toCssColor, fromCssColor , withAlpha + , toCssString ) {-| Helpers for working with colors. @@ -10,6 +11,7 @@ module Nri.Ui.Colors.Extra exposing @docs toCssColor, fromCssColor @docs withAlpha +@docs toCssString -} @@ -44,3 +46,9 @@ withAlpha 0.5 grassland -- "{ value = "rgba(86, 191, 116, 0.5)", color = Compati withAlpha : Float -> Css.Color -> Css.Color withAlpha alpha { red, green, blue } = Css.rgba red green blue alpha + + +{-| -} +toCssString : Css.Color -> String +toCssString = + SolidColor.toRGBString << fromCssColor diff --git a/src/Nri/Ui/SortableTable/V2.elm b/src/Nri/Ui/SortableTable/V2.elm index e6905371..477fb113 100644 --- a/src/Nri/Ui/SortableTable/V2.elm +++ b/src/Nri/Ui/SortableTable/V2.elm @@ -21,11 +21,10 @@ import Css exposing (..) import Html.Styled as Html exposing (Html) import Html.Styled.Attributes exposing (css) import Html.Styled.Events -import Nri.Ui.Colors.Extra +import Nri.Ui.Colors.Extra exposing (toCssString) import Nri.Ui.Colors.V1 import Nri.Ui.CssVendorPrefix.V1 as CssVendorPrefix import Nri.Ui.Table.V5 -import SolidColor import Svg.Styled as Svg import Svg.Styled.Attributes as SvgAttributes @@ -363,8 +362,3 @@ sortArrow direction active = [ Svg.polygon [ SvgAttributes.points "0 6 4 0 8 6 0 6" ] [] ] ] - - -toCssString : Css.Color -> String -toCssString = - SolidColor.toRGBString << Nri.Ui.Colors.Extra.fromCssColor diff --git a/src/Nri/Ui/Switch/V2.elm b/src/Nri/Ui/Switch/V2.elm index a9e42c26..c1e2746d 100644 --- a/src/Nri/Ui/Switch/V2.elm +++ b/src/Nri/Ui/Switch/V2.elm @@ -13,6 +13,7 @@ module Nri.Ui.Switch.V2 exposing - 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 + - Use Colors.azure instead of a hardcoded hex @docs view, label @@ -34,6 +35,7 @@ import Css.Media import Html.Styled as WildWildHtml import Html.Styled.Attributes as Attributes import Html.Styled.Events as Events +import Nri.Ui.Colors.Extra exposing (toCssString) import Nri.Ui.Colors.V1 as Colors import Nri.Ui.Html.Attributes.V2 as Extra import Nri.Ui.Svg.V1 exposing (Svg) @@ -164,8 +166,7 @@ view attrs isOn = , Css.pseudoClass "focus-within" [ Global.descendants [ Global.class "switch-slider" - [ -- azure, but can't use the Color type here - Css.property "stroke" "#146AFF" + [ Css.property "stroke" (toCssString Colors.azure) , Css.property "stroke-width" "3px" ] ] From 7330b06fcce501db3876b3bf55022c5f5c283137 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 18:09:18 -0700 Subject: [PATCH 06/17] Fix all the stroke hardcoded colors --- src/Nri/Ui/Switch/V2.elm | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Nri/Ui/Switch/V2.elm b/src/Nri/Ui/Switch/V2.elm index c1e2746d..51c88b0c 100644 --- a/src/Nri/Ui/Switch/V2.elm +++ b/src/Nri/Ui/Switch/V2.elm @@ -13,7 +13,7 @@ module Nri.Ui.Switch.V2 exposing - 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 - - Use Colors.azure instead of a hardcoded hex + - Use Colors values instead of hardcoded hex strings @docs view, label @@ -29,7 +29,7 @@ module Nri.Ui.Switch.V2 exposing import Accessibility.Styled as Html exposing (Html) import Accessibility.Styled.Aria as Aria import Accessibility.Styled.Widget as Widget -import Css exposing (Style) +import Css exposing (Color, Style) import Css.Global as Global import Css.Media import Html.Styled as WildWildHtml @@ -166,7 +166,7 @@ view attrs isOn = , Css.pseudoClass "focus-within" [ Global.descendants [ Global.class "switch-slider" - [ Css.property "stroke" (toCssString Colors.azure) + [ stroke Colors.azure , Css.property "stroke-width" "3px" ] ] @@ -347,12 +347,10 @@ viewSwitch config = , SvgAttributes.fill "#FFF" , SvgAttributes.css [ if config.isOn then - -- azure, but can't use the Color type here - Css.property "stroke" "#146AFF" + stroke Colors.azure else - -- gray75, but can't use the Color type here - Css.property "stroke" "#BFBFBF" + stroke Colors.gray75 , transition "stroke 0.1s" ] , SvgAttributes.class "switch-slider" @@ -365,11 +363,10 @@ viewSwitch config = , SvgAttributes.d "M8 15.865L12.323 20 21.554 10" , SvgAttributes.css [ if config.isOn then - -- azure, but can't use the Color type here - Css.property "stroke" "#146AFF" + stroke Colors.azure else - Css.property "stroke" "rgba(255,255,255,0)" + stroke Colors.white , transition "stroke 0.2s" ] ] @@ -380,6 +377,11 @@ viewSwitch config = |> Nri.Ui.Svg.V1.fromHtml +stroke : Color -> Style +stroke color = + Css.property "stroke" (toCssString color) + + transition : String -> Css.Style transition transitionRules = Css.Media.withMediaQuery From e964e5a845ea4fb098362b0336ec83361e0c82c0 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 18:14:05 -0700 Subject: [PATCH 07/17] Fix the aria and for placement --- src/Nri/Ui/Switch/V2.elm | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Nri/Ui/Switch/V2.elm b/src/Nri/Ui/Switch/V2.elm index 51c88b0c..0edbc27d 100644 --- a/src/Nri/Ui/Switch/V2.elm +++ b/src/Nri/Ui/Switch/V2.elm @@ -27,16 +27,15 @@ module Nri.Ui.Switch.V2 exposing -} import Accessibility.Styled as Html exposing (Html) -import Accessibility.Styled.Aria as Aria import Accessibility.Styled.Widget as Widget import Css exposing (Color, Style) import Css.Global as Global import Css.Media -import Html.Styled as WildWildHtml import Html.Styled.Attributes as Attributes import Html.Styled.Events as Events import Nri.Ui.Colors.Extra exposing (toCssString) import Nri.Ui.Colors.V1 as Colors +import Nri.Ui.Fonts.V1 as Fonts import Nri.Ui.Html.Attributes.V2 as Extra import Nri.Ui.Svg.V1 exposing (Svg) import Svg.Styled as Svg @@ -118,7 +117,10 @@ containerCss styles = Attribute <| \config -> { config | containerCss = config.containerCss ++ styles } -{-| Adds CSS to the `label` element. +{-| Adds CSS to the element containing the label text. + +Note that these styles don't apply to the literal HTML label element, since it contains the icon SVG as well. + -} labelCss : List Css.Style -> Attribute msg labelCss styles = @@ -157,7 +159,7 @@ view attrs isOn = config = List.foldl (\(Attribute update) -> update) defaultConfig attrs in - WildWildHtml.label + Html.label [ Attributes.id (config.id ++ "-container") , Attributes.css [ Css.display Css.inlineFlex @@ -178,9 +180,9 @@ view attrs isOn = else Css.notAllowed ) + , Css.batch config.containerCss ] - , Aria.controls config.id - , Widget.checked (Just isOn) + , Attributes.for config.id ] [ viewCheckbox { id = config.id @@ -195,15 +197,14 @@ view attrs isOn = , enabled = config.onSwitch /= Nothing } ) - , -- TODO: This element should literally be a label. - -- The `for` attribute is meaningless for a `span`. - Html.span + , Html.span [ Attributes.css [ Css.fontWeight (Css.int 600) , Css.color Colors.navy , Css.paddingLeft (Css.px 5) + , Fonts.baseFont + , Css.batch config.labelCss ] - , Attributes.for config.id ] [ Html.text config.label ] ] From 871207c7aa47c29acb963d0cf9eaf894826ac20b Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 18:16:27 -0700 Subject: [PATCH 08/17] implement disabling --- src/Nri/Ui/Switch/V2.elm | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Nri/Ui/Switch/V2.elm b/src/Nri/Ui/Switch/V2.elm index 0edbc27d..d8256adb 100644 --- a/src/Nri/Ui/Switch/V2.elm +++ b/src/Nri/Ui/Switch/V2.elm @@ -187,7 +187,8 @@ view attrs isOn = [ viewCheckbox { id = config.id , onCheck = config.onSwitch - , checked = isOn + , isDisabled = config.isDisabled + , selected = isOn , custom = config.custom } , Nri.Ui.Svg.V1.toHtml @@ -213,13 +214,14 @@ view attrs isOn = viewCheckbox : { id : String , onCheck : Maybe (Bool -> msg) - , checked : Bool + , selected : Bool + , isDisabled : Bool , custom : List (Html.Attribute Never) } -> Html msg viewCheckbox config = Html.checkbox config.id - (Just config.checked) + (Just config.selected) ([ Attributes.id config.id , Attributes.css [ Css.position Css.absolute @@ -228,11 +230,11 @@ viewCheckbox config = , Css.zIndex (Css.int 0) , Css.opacity (Css.num 0) ] - , case config.onCheck of - Just onCheck -> + , case ( config.onCheck, config.isDisabled ) of + ( Just onCheck, False ) -> Events.onCheck onCheck - Nothing -> + _ -> Widget.disabled True ] ++ List.map (Attributes.map never) config.custom From 0d8d2588711ebf369979e8c163fea478a9f6475f Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 18:20:22 -0700 Subject: [PATCH 09/17] Move the status of the switch to the list api --- src/Nri/Ui/Switch/V2.elm | 30 +++++++++++++++++++++--------- styleguide-app/Examples/Switch.elm | 18 +++++++++--------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/Nri/Ui/Switch/V2.elm b/src/Nri/Ui/Switch/V2.elm index d8256adb..968a7d13 100644 --- a/src/Nri/Ui/Switch/V2.elm +++ b/src/Nri/Ui/Switch/V2.elm @@ -1,6 +1,7 @@ module Nri.Ui.Switch.V2 exposing ( view, label , Attribute + , selected , containerCss, labelCss, custom, nriDescription, id, testId , onSwitch, disabled, enabled ) @@ -14,6 +15,7 @@ module Nri.Ui.Switch.V2 exposing - 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 - Use Colors values instead of hardcoded hex strings + - Move the status (selected or not selected) to the list api @docs view, label @@ -21,6 +23,7 @@ module Nri.Ui.Switch.V2 exposing ### Attributes @docs Attribute +@docs selected @docs containerCss, labelCss, custom, nriDescription, id, testId @docs onSwitch, disabled, enabled @@ -47,6 +50,13 @@ type Attribute msg = Attribute (Config msg -> Config msg) +{-| What is the status of the Switch, selected or not? +-} +selected : Bool -> Attribute msg +selected isSelected = + Attribute <| \config -> { config | isSelected = isSelected } + + {-| Specify what happens when the switch is toggled. -} onSwitch : (Bool -> msg) -> Attribute msg @@ -134,6 +144,7 @@ type alias Config msg = , containerCss : List Style , labelCss : List Style , isDisabled : Bool + , isSelected : Bool , custom : List (Html.Attribute Never) } @@ -146,6 +157,7 @@ defaultConfig = , containerCss = [] , labelCss = [] , isDisabled = False + , isSelected = False , custom = [] } @@ -153,8 +165,8 @@ defaultConfig = {-| Render a switch. The boolean here indicates whether the switch is on or not. -} -view : List (Attribute msg) -> Bool -> Html msg -view attrs isOn = +view : List (Attribute msg) -> Html msg +view attrs = let config = List.foldl (\(Attribute update) -> update) defaultConfig attrs @@ -188,13 +200,13 @@ view attrs isOn = { id = config.id , onCheck = config.onSwitch , isDisabled = config.isDisabled - , selected = isOn + , selected = config.isSelected , custom = config.custom } , Nri.Ui.Svg.V1.toHtml (viewSwitch { id = config.id - , isOn = isOn + , isSelected = config.isSelected , enabled = config.onSwitch /= Nothing } ) @@ -243,7 +255,7 @@ viewCheckbox config = viewSwitch : { id : String - , isOn : Bool + , isSelected : Bool , enabled : Bool } -> Svg @@ -317,7 +329,7 @@ viewSwitch config = [ Svg.use [ SvgAttributes.xlinkHref ("#" ++ shadowBoxId) , SvgAttributes.css - [ if config.isOn then + [ if config.isSelected then Css.fill Colors.glacier else @@ -335,7 +347,7 @@ viewSwitch config = ] , Svg.g [ SvgAttributes.css - [ if config.isOn then + [ if config.isSelected then Css.transform (Css.translateX (Css.px 11)) else @@ -349,7 +361,7 @@ viewSwitch config = , SvgAttributes.r "14.5" , SvgAttributes.fill "#FFF" , SvgAttributes.css - [ if config.isOn then + [ if config.isSelected then stroke Colors.azure else @@ -365,7 +377,7 @@ viewSwitch config = , SvgAttributes.strokeWidth "3" , SvgAttributes.d "M8 15.865L12.323 20 21.554 10" , SvgAttributes.css - [ if config.isOn then + [ if config.isSelected then stroke Colors.azure else diff --git a/styleguide-app/Examples/Switch.elm b/styleguide-app/Examples/Switch.elm index 1c554b09..8d5910e5 100644 --- a/styleguide-app/Examples/Switch.elm +++ b/styleguide-app/Examples/Switch.elm @@ -33,15 +33,15 @@ example = , subscriptions = \_ -> Sub.none , preview = [ Switch.view - [ Switch.label "Toggle On" - , Switch.custom [ Key.tabbable False ] - ] - False - , Switch.view [ Switch.label "Toggle Off" + , Switch.selected False + , Switch.custom [ Key.tabbable False ] + ] + , Switch.view + [ Switch.label "Toggle On" + , Switch.selected True , Switch.custom [ Key.tabbable False ] ] - True ] , view = \ellieLinkConfig interactiveIsOn -> @@ -56,22 +56,22 @@ example = else "Off" ) + , Switch.selected interactiveIsOn ] - interactiveIsOn , Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Disabled (On)" ] , Switch.view [ Switch.disabled , Switch.id "switch-disabled-on" , Switch.label "Permanently on" + , Switch.selected True ] - True , Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Disabled (Off)" ] , Switch.view [ Switch.disabled , Switch.id "switch-disabled-off" , Switch.label "Permanently off" + , Switch.selected False ] - False ] , categories = [ Category.Inputs ] , keyboardSupport = [{- TODO -}] From fc40dafa37d6eb341f784d5d5d28bbf0d35299d0 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 18:25:51 -0700 Subject: [PATCH 10/17] Id and label should reeeaaally always be passed in for robustness --- src/Nri/Ui/Switch/V2.elm | 44 ++++++++---------------------- styleguide-app/Examples/Switch.elm | 31 +++++++++------------ 2 files changed, 25 insertions(+), 50 deletions(-) diff --git a/src/Nri/Ui/Switch/V2.elm b/src/Nri/Ui/Switch/V2.elm index 968a7d13..18ac65b3 100644 --- a/src/Nri/Ui/Switch/V2.elm +++ b/src/Nri/Ui/Switch/V2.elm @@ -1,8 +1,8 @@ module Nri.Ui.Switch.V2 exposing - ( view, label + ( view , Attribute , selected - , containerCss, labelCss, custom, nriDescription, id, testId + , containerCss, labelCss, custom, nriDescription, testId , onSwitch, disabled, enabled ) @@ -16,15 +16,16 @@ module Nri.Ui.Switch.V2 exposing - extends API to be more consistent with other form/control components - Use Colors values instead of hardcoded hex strings - Move the status (selected or not selected) to the list api + - REQUIRE label and id always -@docs view, label +@docs view ### Attributes @docs Attribute @docs selected -@docs containerCss, labelCss, custom, nriDescription, id, testId +@docs containerCss, labelCss, custom, nriDescription, testId @docs onSwitch, disabled, enabled -} @@ -79,23 +80,6 @@ enabled = Attribute <| \config -> { config | isDisabled = False } -{-| Set the HTML ID of the switch toggle. If you have only one on the page, -you don't need to set this, but you should definitely set it if you have -more than one. --} -id : String -> Attribute msg -id id_ = - Attribute <| \config -> { config | id = id_ } - - -{-| Add labeling text to the switch. This text should be descriptive and -able to be displayed inline. --} -label : String -> Attribute msg -label label_ = - Attribute <| \config -> { config | label = label_ } - - {-| 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 @@ -139,8 +123,6 @@ labelCss styles = type alias Config msg = { onSwitch : Maybe (Bool -> msg) - , id : String - , label : String , containerCss : List Style , labelCss : List Style , isDisabled : Bool @@ -152,8 +134,6 @@ type alias Config msg = defaultConfig : Config msg defaultConfig = { onSwitch = Nothing - , id = "nri-ui-switch-with-default-id" - , label = "" , containerCss = [] , labelCss = [] , isDisabled = False @@ -165,14 +145,14 @@ defaultConfig = {-| Render a switch. The boolean here indicates whether the switch is on or not. -} -view : List (Attribute msg) -> Html msg -view attrs = +view : { label : String, id : String } -> List (Attribute msg) -> Html msg +view { label, id } attrs = let config = List.foldl (\(Attribute update) -> update) defaultConfig attrs in Html.label - [ Attributes.id (config.id ++ "-container") + [ Attributes.id (id ++ "-container") , Attributes.css [ Css.display Css.inlineFlex , Css.alignItems Css.center @@ -194,10 +174,10 @@ view attrs = ) , Css.batch config.containerCss ] - , Attributes.for config.id + , Attributes.for id ] [ viewCheckbox - { id = config.id + { id = id , onCheck = config.onSwitch , isDisabled = config.isDisabled , selected = config.isSelected @@ -205,7 +185,7 @@ view attrs = } , Nri.Ui.Svg.V1.toHtml (viewSwitch - { id = config.id + { id = id , isSelected = config.isSelected , enabled = config.onSwitch /= Nothing } @@ -219,7 +199,7 @@ view attrs = , Css.batch config.labelCss ] ] - [ Html.text config.label ] + [ Html.text label ] ] diff --git a/styleguide-app/Examples/Switch.elm b/styleguide-app/Examples/Switch.elm index 8d5910e5..17bc6641 100644 --- a/styleguide-app/Examples/Switch.elm +++ b/styleguide-app/Examples/Switch.elm @@ -32,14 +32,12 @@ example = , update = \(Switch new) _ -> ( new, Cmd.none ) , subscriptions = \_ -> Sub.none , preview = - [ Switch.view - [ Switch.label "Toggle Off" - , Switch.selected False + [ Switch.view { label = "Toggle Off", id = "preview-switch-a" } + [ Switch.selected False , Switch.custom [ Key.tabbable False ] ] - , Switch.view - [ Switch.label "Toggle On" - , Switch.selected True + , Switch.view { label = "Toggle On", id = "preview-switch-b" } + [ Switch.selected True , Switch.custom [ Key.tabbable False ] ] ] @@ -47,29 +45,26 @@ example = \ellieLinkConfig interactiveIsOn -> [ Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Interactive" ] , Switch.view + { id = "switch-interactive" + , label = "Show pandas in results" + } [ Switch.onSwitch Switch - , Switch.id "switch-interactive" - , Switch.label - (if interactiveIsOn then - "On" - - else - "Off" - ) , Switch.selected interactiveIsOn ] , Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Disabled (On)" ] , Switch.view + { id = "switch-disabled-on" + , label = "Permanently on" + } [ Switch.disabled - , Switch.id "switch-disabled-on" - , Switch.label "Permanently on" , Switch.selected True ] , Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Disabled (Off)" ] , Switch.view + { id = "switch-disabled-off" + , label = "Permanently off" + } [ Switch.disabled - , Switch.id "switch-disabled-off" - , Switch.label "Permanently off" , Switch.selected False ] ] From 24c5ce43bb10028566461a7ecef09ca29609a556 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 18:27:24 -0700 Subject: [PATCH 11/17] Move custom attributes to the container --- src/Nri/Ui/Switch/V2.elm | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Nri/Ui/Switch/V2.elm b/src/Nri/Ui/Switch/V2.elm index 18ac65b3..5f8f05e6 100644 --- a/src/Nri/Ui/Switch/V2.elm +++ b/src/Nri/Ui/Switch/V2.elm @@ -17,6 +17,7 @@ module Nri.Ui.Switch.V2 exposing - Use Colors values instead of hardcoded hex strings - Move the status (selected or not selected) to the list api - REQUIRE label and id always + - Move custom attributes to the container @docs view @@ -152,8 +153,8 @@ view { label, id } attrs = List.foldl (\(Attribute update) -> update) defaultConfig attrs in Html.label - [ Attributes.id (id ++ "-container") - , Attributes.css + ([ Attributes.id (id ++ "-container") + , Attributes.css [ Css.display Css.inlineFlex , Css.alignItems Css.center , Css.position Css.relative @@ -174,14 +175,15 @@ view { label, id } attrs = ) , Css.batch config.containerCss ] - , Attributes.for id - ] + , Attributes.for id + ] + ++ List.map (Attributes.map never) config.custom + ) [ viewCheckbox { id = id , onCheck = config.onSwitch , isDisabled = config.isDisabled , selected = config.isSelected - , custom = config.custom } , Nri.Ui.Svg.V1.toHtml (viewSwitch @@ -208,29 +210,26 @@ viewCheckbox : , onCheck : Maybe (Bool -> msg) , selected : Bool , isDisabled : Bool - , custom : List (Html.Attribute Never) } -> Html msg viewCheckbox config = Html.checkbox config.id (Just config.selected) - ([ Attributes.id config.id - , Attributes.css + [ Attributes.id config.id + , Attributes.css [ Css.position Css.absolute , Css.top (Css.px 10) , Css.left (Css.px 10) , Css.zIndex (Css.int 0) , Css.opacity (Css.num 0) ] - , case ( config.onCheck, config.isDisabled ) of + , case ( config.onCheck, config.isDisabled ) of ( Just onCheck, False ) -> Events.onCheck onCheck _ -> Widget.disabled True - ] - ++ List.map (Attributes.map never) config.custom - ) + ] viewSwitch : From cd1a4a05490bf3ad160ef4775f4112527ad8693b Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 18:37:32 -0700 Subject: [PATCH 12/17] Fix switch version --- styleguide-app/Examples/Switch.elm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/styleguide-app/Examples/Switch.elm b/styleguide-app/Examples/Switch.elm index 17bc6641..ffb756a8 100644 --- a/styleguide-app/Examples/Switch.elm +++ b/styleguide-app/Examples/Switch.elm @@ -27,7 +27,7 @@ type Msg example : Example State Msg example = { name = "Switch" - , version = 1 + , version = 2 , state = True , update = \(Switch new) _ -> ( new, Cmd.none ) , subscriptions = \_ -> Sub.none From 659ad03471a335c56c914b6016a1a1f1badef43b Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 18:38:46 -0700 Subject: [PATCH 13/17] Ad keyboard support notes --- styleguide-app/Examples/Switch.elm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/styleguide-app/Examples/Switch.elm b/styleguide-app/Examples/Switch.elm index ffb756a8..1f3a0fc4 100644 --- a/styleguide-app/Examples/Switch.elm +++ b/styleguide-app/Examples/Switch.elm @@ -10,6 +10,7 @@ import Accessibility.Styled.Key as Key import Category import Example exposing (Example) import Html.Styled as Html +import KeyboardSupport exposing (Key(..)) import Nri.Ui.Heading.V2 as Heading import Nri.Ui.Switch.V2 as Switch @@ -69,5 +70,9 @@ example = ] ] , categories = [ Category.Inputs ] - , keyboardSupport = [{- TODO -}] + , keyboardSupport = + [ { keys = [ Space ] + , result = "Toggle the Switch state" + } + ] } From a52c6c785f6a5877e81e25c286e2d66ee69d9090 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 18:57:22 -0700 Subject: [PATCH 14/17] Wire up a basic controls example --- styleguide-app/Debug/Control/View.elm | 9 +- styleguide-app/Examples/Switch.elm | 134 +++++++++++++++++++------- 2 files changed, 108 insertions(+), 35 deletions(-) diff --git a/styleguide-app/Debug/Control/View.elm b/styleguide-app/Debug/Control/View.elm index b4b75f7b..66554a95 100644 --- a/styleguide-app/Debug/Control/View.elm +++ b/styleguide-app/Debug/Control/View.elm @@ -1,4 +1,4 @@ -module Debug.Control.View exposing (codeFromList, codeFromListWithIndentLevel, view) +module Debug.Control.View exposing (codeFromList, codeFromListWithHardcoded, codeFromListWithIndentLevel, view) import Css exposing (..) import Css.Media exposing (withMedia) @@ -97,6 +97,13 @@ viewSection name children = ) +codeFromListWithHardcoded : List String -> List ( String, a ) -> String +codeFromListWithHardcoded hardcodes elements = + List.map (\v -> ( v, () )) hardcodes + ++ List.map (Tuple.mapSecond (always ())) elements + |> codeFromList + + codeFromList : List ( String, a ) -> String codeFromList = codeFromListWithIndentLevel 1 diff --git a/styleguide-app/Examples/Switch.elm b/styleguide-app/Examples/Switch.elm index 1f3a0fc4..c3a2882a 100644 --- a/styleguide-app/Examples/Switch.elm +++ b/styleguide-app/Examples/Switch.elm @@ -8,6 +8,9 @@ module Examples.Switch exposing (Msg, State, example) import Accessibility.Styled.Key as Key import Category +import Debug.Control as Control exposing (Control) +import Debug.Control.Extra as ControlExtra +import Debug.Control.View as ControlView import Example exposing (Example) import Html.Styled as Html import KeyboardSupport exposing (Key(..)) @@ -15,22 +18,22 @@ import Nri.Ui.Heading.V2 as Heading import Nri.Ui.Switch.V2 as Switch -{-| -} -type alias State = - Bool +moduleName : String +moduleName = + "Switch" -{-| -} -type Msg - = Switch Bool +version : Int +version = + 2 example : Example State Msg example = - { name = "Switch" - , version = 2 - , state = True - , update = \(Switch new) _ -> ( new, Cmd.none ) + { name = moduleName + , version = version + , state = init + , update = update , subscriptions = \_ -> Sub.none , preview = [ Switch.view { label = "Toggle Off", id = "preview-switch-a" } @@ -43,31 +46,42 @@ example = ] ] , view = - \ellieLinkConfig interactiveIsOn -> - [ Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Interactive" ] - , Switch.view - { id = "switch-interactive" - , label = "Show pandas in results" + \ellieLinkConfig state -> + let + currentValue = + Control.currentValue state.settings + in + [ ControlView.view + { ellieLinkConfig = ellieLinkConfig + , name = moduleName + , version = version + , update = UpdateSettings + , settings = state.settings + , mainType = "RootHtml.Html msg" + , extraImports = [] + , toExampleCode = + \{ label, attributes } -> + [ { sectionName = "Example" + , code = + moduleName + ++ ".view" + ++ " \"" + ++ label + ++ "\"\t" + ++ ControlView.codeFromListWithHardcoded + [ "Switch.selected " + ++ Debug.toString state.selected + ++ "\n-- , Switch.onSwitch Switch -- <- you'll need to wire in a Msg for the Switch to work" + ] + attributes + } + ] } - [ Switch.onSwitch Switch - , Switch.selected interactiveIsOn - ] - , Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Disabled (On)" ] - , Switch.view - { id = "switch-disabled-on" - , label = "Permanently on" - } - [ Switch.disabled - , Switch.selected True - ] - , Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Disabled (Off)" ] - , Switch.view - { id = "switch-disabled-off" - , label = "Permanently off" - } - [ Switch.disabled - , Switch.selected False - ] + , Switch.view { label = currentValue.label, id = "view-switch-example" } + (Switch.selected state.selected + :: Switch.onSwitch Switch + :: List.map Tuple.second currentValue.attributes + ) ] , categories = [ Category.Inputs ] , keyboardSupport = @@ -76,3 +90,55 @@ example = } ] } + + +{-| -} +type alias State = + { selected : Bool + , settings : Control Settings + } + + +init : State +init = + { selected = True + , settings = controlSettings + } + + +type alias Settings = + { label : String + , attributes : List ( String, Switch.Attribute Msg ) + } + + +controlSettings : Control Settings +controlSettings = + Control.record Settings + |> Control.field "label" (Control.string "Show pandas in results") + |> Control.field "attributes" initAttributes + + +initAttributes : Control (List ( String, Switch.Attribute msg )) +initAttributes = + ControlExtra.list + + +{-| -} +type Msg + = Switch Bool + | UpdateSettings (Control Settings) + + +update : Msg -> State -> ( State, Cmd Msg ) +update msg state = + case msg of + Switch bool -> + ( { state | selected = bool } + , Cmd.none + ) + + UpdateSettings settings -> + ( { state | settings = settings } + , Cmd.none + ) From 34cd3894a5a2be9b8b6483d411b045c11ecd4d92 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 19:00:21 -0700 Subject: [PATCH 15/17] Adds disabled attribute example --- src/Nri/Ui/Switch/V2.elm | 17 ++++++----------- styleguide-app/Examples/Switch.elm | 2 ++ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/Nri/Ui/Switch/V2.elm b/src/Nri/Ui/Switch/V2.elm index 5f8f05e6..ed40a732 100644 --- a/src/Nri/Ui/Switch/V2.elm +++ b/src/Nri/Ui/Switch/V2.elm @@ -3,7 +3,7 @@ module Nri.Ui.Switch.V2 exposing , Attribute , selected , containerCss, labelCss, custom, nriDescription, testId - , onSwitch, disabled, enabled + , onSwitch, disabled ) {-| @@ -18,6 +18,7 @@ module Nri.Ui.Switch.V2 exposing - Move the status (selected or not selected) to the list api - REQUIRE label and id always - Move custom attributes to the container + - change disabled to take a bool (which I think is the slighty more common pattern) @docs view @@ -27,7 +28,7 @@ module Nri.Ui.Switch.V2 exposing @docs Attribute @docs selected @docs containerCss, labelCss, custom, nriDescription, testId -@docs onSwitch, disabled, enabled +@docs onSwitch, disabled -} @@ -70,15 +71,9 @@ onSwitch onSwitch_ = specify `onSwitch`, this is the default, but it's provided so you don't have to resort to `filterMap` or similar to build a clean list of attributes. -} -disabled : Attribute msg -disabled = - Attribute <| \config -> { config | isDisabled = True } - - -{-| -} -enabled : Attribute msg -enabled = - Attribute <| \config -> { config | isDisabled = False } +disabled : Bool -> Attribute msg +disabled isDisabled = + Attribute <| \config -> { config | isDisabled = isDisabled } {-| Pass custom attributes through to be attached to the underlying input. diff --git a/styleguide-app/Examples/Switch.elm b/styleguide-app/Examples/Switch.elm index c3a2882a..fbeb2333 100644 --- a/styleguide-app/Examples/Switch.elm +++ b/styleguide-app/Examples/Switch.elm @@ -8,6 +8,7 @@ module Examples.Switch exposing (Msg, State, example) import Accessibility.Styled.Key as Key import Category +import CommonControls import Debug.Control as Control exposing (Control) import Debug.Control.Extra as ControlExtra import Debug.Control.View as ControlView @@ -122,6 +123,7 @@ controlSettings = initAttributes : Control (List ( String, Switch.Attribute msg )) initAttributes = ControlExtra.list + |> CommonControls.disabledListItem moduleName Switch.disabled {-| -} From 1b5a92867e8e442da6d5e662fec0080767c985cb Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 19:02:52 -0700 Subject: [PATCH 16/17] Fix the disabled attribute to work all the way --- src/Nri/Ui/Switch/V2.elm | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Nri/Ui/Switch/V2.elm b/src/Nri/Ui/Switch/V2.elm index ed40a732..0dceb02e 100644 --- a/src/Nri/Ui/Switch/V2.elm +++ b/src/Nri/Ui/Switch/V2.elm @@ -146,6 +146,9 @@ view { label, id } attrs = let config = List.foldl (\(Attribute update) -> update) defaultConfig attrs + + notOperable = + config.onSwitch == Nothing || config.isDisabled in Html.label ([ Attributes.id (id ++ "-container") @@ -162,11 +165,11 @@ view { label, id } attrs = ] ] , Css.cursor - (if config.onSwitch /= Nothing then - Css.pointer + (if notOperable then + Css.notAllowed else - Css.notAllowed + Css.pointer ) , Css.batch config.containerCss ] @@ -184,7 +187,7 @@ view { label, id } attrs = (viewSwitch { id = id , isSelected = config.isSelected - , enabled = config.onSwitch /= Nothing + , isDisabled = notOperable } ) , Html.span @@ -230,7 +233,7 @@ viewCheckbox config = viewSwitch : { id : String , isSelected : Bool - , enabled : Bool + , isDisabled : Bool } -> Svg viewSwitch config = @@ -247,11 +250,11 @@ viewSwitch config = , SvgAttributes.viewBox "0 0 43 32" , SvgAttributes.css [ Css.zIndex (Css.int 1) - , if config.enabled then - Css.opacity (Css.num 1) + , if config.isDisabled then + Css.opacity (Css.num 0.4) else - Css.opacity (Css.num 0.4) + Css.opacity (Css.num 1) ] ] [ Svg.defs [] From fc6cf001399cda9e1eddf9c3cbf0a55b2f07bd36 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Mon, 18 Apr 2022 19:11:02 -0700 Subject: [PATCH 17/17] Fix tests --- styleguide-app/Examples/Switch.elm | 2 -- styleguide/tests/SwitchExampleSpec.elm | 17 +++++------------ 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/styleguide-app/Examples/Switch.elm b/styleguide-app/Examples/Switch.elm index fbeb2333..9fc3c05a 100644 --- a/styleguide-app/Examples/Switch.elm +++ b/styleguide-app/Examples/Switch.elm @@ -13,9 +13,7 @@ import Debug.Control as Control exposing (Control) import Debug.Control.Extra as ControlExtra import Debug.Control.View as ControlView import Example exposing (Example) -import Html.Styled as Html import KeyboardSupport exposing (Key(..)) -import Nri.Ui.Heading.V2 as Heading import Nri.Ui.Switch.V2 as Switch diff --git a/styleguide/tests/SwitchExampleSpec.elm b/styleguide/tests/SwitchExampleSpec.elm index fb28f262..ea58696d 100644 --- a/styleguide/tests/SwitchExampleSpec.elm +++ b/styleguide/tests/SwitchExampleSpec.elm @@ -1,6 +1,5 @@ module SwitchExampleSpec exposing (suite) -import Accessibility.Aria as Aria import ProgramTest exposing (..) import Routes exposing (Route) import Test exposing (..) @@ -20,17 +19,11 @@ suite = \() -> app route |> ensureViewHas [ text "Nri.Ui.Switch" ] - -- switch starts with aria-checked=true and text "On" - |> ensureViewHas - [ attribute (Aria.checked (Just True)) - , text "On" - ] + -- switch starts with checked=true + |> ensureViewHas [ checked True ] -- user can click the first switch - |> check "switch-interactive" "On" False - -- the switch now has aria-checked=false and text "Off" - |> ensureViewHas - [ attribute (Aria.checked (Just False)) - , text "Off" - ] + |> check "view-switch-example" "Show pandas in results" False + -- the switch now has checked=false + |> ensureViewHas [ checked False ] |> done ]