mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-12-23 05:31:49 +03:00
Merge pull request #787 from NoRedInk/kraken/radiobutton-v3
Create RadioButton V3
This commit is contained in:
commit
21244543ca
@ -1,6 +1,7 @@
|
||||
Nri.Ui.Accordion.V1,upgrade to V3
|
||||
Nri.Ui.Menu.V1,upgrade to V3
|
||||
Nri.Ui.Menu.V2,upgrade to V3
|
||||
Nri.Ui.RadioButton.V2,upgrade to V3
|
||||
Nri.Ui.Table.V4,upgrade to V5
|
||||
Nri.Ui.Tabs.V6,upgrade to V7
|
||||
Nri.Ui.Tooltip.V1,upgrade to V2
|
||||
|
|
1
elm.json
1
elm.json
@ -44,6 +44,7 @@
|
||||
"Nri.Ui.Pennant.V2",
|
||||
"Nri.Ui.PremiumCheckbox.V6",
|
||||
"Nri.Ui.RadioButton.V2",
|
||||
"Nri.Ui.RadioButton.V3",
|
||||
"Nri.Ui.SegmentedControl.V14",
|
||||
"Nri.Ui.Select.V8",
|
||||
"Nri.Ui.Slide.V1",
|
||||
|
@ -81,6 +81,9 @@ hint = 'upgrade to V11'
|
||||
[forbidden."Nri.Ui.RadioButton.V1"]
|
||||
hint = 'upgrade to V2'
|
||||
|
||||
[forbidden."Nri.Ui.RadioButton.V2"]
|
||||
hint = 'upgrade to V3'
|
||||
|
||||
[forbidden."Nri.Ui.SegmentedControl.V11"]
|
||||
hint = 'upgrade to V14'
|
||||
|
||||
|
636
src/Nri/Ui/RadioButton/V3.elm
Normal file
636
src/Nri/Ui/RadioButton/V3.elm
Normal file
@ -0,0 +1,636 @@
|
||||
module Nri.Ui.RadioButton.V3 exposing
|
||||
( view
|
||||
, premium, showPennant
|
||||
, disclosure
|
||||
, onSelect
|
||||
, Attribute
|
||||
, hiddenLabel, visibleLabel
|
||||
, containerCss, custom, nriDescription, id, testId
|
||||
, disabled, enabled, errorIf, errorMessage, guidance
|
||||
)
|
||||
|
||||
{-| Changes from V2:
|
||||
|
||||
- list based API instead of record based
|
||||
- add disclosure to show rich content when the radio is selected
|
||||
- allow customization of the id
|
||||
|
||||
@docs view
|
||||
|
||||
|
||||
### Content
|
||||
|
||||
@docs premium, showPennant
|
||||
@docs disclosure
|
||||
|
||||
|
||||
### Event handlers
|
||||
|
||||
@docs onSelect
|
||||
|
||||
|
||||
### Attributes
|
||||
|
||||
@docs Attribute
|
||||
@docs hiddenLabel, visibleLabel
|
||||
@docs containerCss, custom, nriDescription, id, testId
|
||||
@docs disabled, enabled, errorIf, errorMessage, guidance
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled exposing (..)
|
||||
import Accessibility.Styled.Aria as Aria
|
||||
import Accessibility.Styled.Style as Style
|
||||
import Accessibility.Styled.Widget as Widget
|
||||
import Css as Css exposing (..)
|
||||
import Css.Global
|
||||
import Html.Styled as Html
|
||||
import Html.Styled.Attributes as Attributes exposing (class, classList, css, for)
|
||||
import Html.Styled.Events exposing (onClick, stopPropagationOn)
|
||||
import InputErrorAndGuidanceInternal exposing (ErrorState, Guidance)
|
||||
import Json.Decode
|
||||
import Nri.Ui.ClickableSvg.V2 as ClickableSvg
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Data.PremiumLevel as PremiumLevel exposing (PremiumLevel)
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Html.Attributes.V2 as Extra
|
||||
import Nri.Ui.Html.V3 exposing (viewJust)
|
||||
import Nri.Ui.Pennant.V2 as Pennant
|
||||
import Nri.Ui.Svg.V1 exposing (Svg, fromHtml)
|
||||
import String exposing (toLower)
|
||||
import String.Extra exposing (dasherize)
|
||||
import Svg.Styled as Svg
|
||||
import Svg.Styled.Attributes as SvgAttributes
|
||||
|
||||
|
||||
{-| This disables the input
|
||||
-}
|
||||
disabled : Attribute value msg
|
||||
disabled =
|
||||
Attribute <| \config -> { config | isDisabled = True }
|
||||
|
||||
|
||||
{-| This enables the input, this is the default behavior
|
||||
-}
|
||||
enabled : Attribute value msg
|
||||
enabled =
|
||||
Attribute <| \config -> { config | isDisabled = False }
|
||||
|
||||
|
||||
{-| Sets whether or not the field will be highlighted as having a validation error.
|
||||
-}
|
||||
errorIf : Bool -> Attribute value msg
|
||||
errorIf =
|
||||
Attribute << InputErrorAndGuidanceInternal.setErrorIf
|
||||
|
||||
|
||||
{-| If `Just`, the field will be highlighted as having a validation error,
|
||||
and the given error message will be shown.
|
||||
-}
|
||||
errorMessage : Maybe String -> Attribute value msg
|
||||
errorMessage =
|
||||
Attribute << InputErrorAndGuidanceInternal.setErrorMessage
|
||||
|
||||
|
||||
{-| A guidance message shows below the input, unless an error message is showing instead.
|
||||
-}
|
||||
guidance : String -> Attribute value msg
|
||||
guidance =
|
||||
Attribute << InputErrorAndGuidanceInternal.setGuidance
|
||||
|
||||
|
||||
{-| Fire a message parameterized by the value type when selecting a radio option
|
||||
-}
|
||||
onSelect : (value -> msg) -> Attribute value msg
|
||||
onSelect onSelect_ =
|
||||
Attribute <| \config -> { config | onSelect = Just onSelect_ }
|
||||
|
||||
|
||||
{-| Lock Premium content if the user does not have Premium.
|
||||
-}
|
||||
premium :
|
||||
{ teacherPremiumLevel : PremiumLevel
|
||||
, contentPremiumLevel : PremiumLevel
|
||||
}
|
||||
-> Attribute value msg
|
||||
premium { teacherPremiumLevel, contentPremiumLevel } =
|
||||
Attribute <|
|
||||
\config ->
|
||||
{ config
|
||||
| teacherPremiumLevel = Just teacherPremiumLevel
|
||||
, contentPremiumLevel = Just contentPremiumLevel
|
||||
}
|
||||
|
||||
|
||||
{-| Show Premium pennant on Premium content.
|
||||
|
||||
When the pennant is clicked, the msg that's passed in will fire.
|
||||
|
||||
For RadioButton.V4, consider removing `showPennant` from the API.
|
||||
|
||||
-}
|
||||
showPennant : msg -> Attribute value msg
|
||||
showPennant premiumMsg =
|
||||
Attribute <| \config -> { config | premiumMsg = Just premiumMsg }
|
||||
|
||||
|
||||
{-| Content that shows when this RadioButton is selected
|
||||
-}
|
||||
disclosure : List (Html msg) -> Attribute value msg
|
||||
disclosure childNodes =
|
||||
Attribute <| \config -> { config | disclosedContent = childNodes }
|
||||
|
||||
|
||||
{-| Adds CSS to the element containing the input.
|
||||
-}
|
||||
containerCss : List Css.Style -> Attribute value msg
|
||||
containerCss styles =
|
||||
Attribute <| \config -> { config | containerCss = config.containerCss ++ styles }
|
||||
|
||||
|
||||
{-| Hides the visible label. (There will still be an invisible label for screen readers.)
|
||||
-}
|
||||
hiddenLabel : Attribute value msg
|
||||
hiddenLabel =
|
||||
Attribute <| \config -> { config | hideLabel = True }
|
||||
|
||||
|
||||
{-| Shows the visible label. This is the default behavior
|
||||
-}
|
||||
visibleLabel : Attribute value msg
|
||||
visibleLabel =
|
||||
Attribute <| \config -> { config | hideLabel = False }
|
||||
|
||||
|
||||
{-| Set a custom ID for this text input and label. If you don't set this,
|
||||
we'll automatically generate one from the label you pass in, but this can
|
||||
cause problems if you have more than one radio input with the same label on
|
||||
the page. You might also use this helper if you're manually managing focus.
|
||||
-}
|
||||
id : String -> Attribute value msg
|
||||
id id_ =
|
||||
Attribute <| \config -> { config | id = Just id_ }
|
||||
|
||||
|
||||
{-| Use this helper to add custom attributes.
|
||||
|
||||
Do NOT use this helper to add css styles, as they may not be applied the way
|
||||
you want/expect if underlying styles change.
|
||||
Instead, please use the `css` helper.
|
||||
|
||||
-}
|
||||
custom : List (Html.Attribute Never) -> Attribute value msg
|
||||
custom attributes =
|
||||
Attribute <| \config -> { config | custom = config.custom ++ attributes }
|
||||
|
||||
|
||||
{-| -}
|
||||
nriDescription : String -> Attribute value msg
|
||||
nriDescription description =
|
||||
custom [ Extra.nriDescription description ]
|
||||
|
||||
|
||||
{-| -}
|
||||
testId : String -> Attribute value msg
|
||||
testId id_ =
|
||||
custom [ Extra.testId id_ ]
|
||||
|
||||
|
||||
{-| Customizations for the RadioButton.
|
||||
-}
|
||||
type Attribute value msg
|
||||
= Attribute (Config value msg -> Config value msg)
|
||||
|
||||
|
||||
{-| This is private. The public API only exposes `Attribute`.
|
||||
-}
|
||||
type alias Config value msg =
|
||||
{ name : Maybe String
|
||||
, id : Maybe String
|
||||
, teacherPremiumLevel : Maybe PremiumLevel
|
||||
, contentPremiumLevel : Maybe PremiumLevel
|
||||
, isDisabled : Bool
|
||||
, guidance : Guidance
|
||||
, error : ErrorState
|
||||
, showPennant : Bool
|
||||
, hideLabel : Bool
|
||||
, containerCss : List Css.Style
|
||||
, custom : List (Html.Attribute Never)
|
||||
, onSelect : Maybe (value -> msg)
|
||||
, premiumMsg : Maybe msg
|
||||
, disclosedContent : List (Html msg)
|
||||
}
|
||||
|
||||
|
||||
emptyConfig : Config value msg
|
||||
emptyConfig =
|
||||
{ name = Nothing
|
||||
, id = Nothing
|
||||
, teacherPremiumLevel = Nothing
|
||||
, contentPremiumLevel = Nothing
|
||||
, isDisabled = False
|
||||
, guidance = InputErrorAndGuidanceInternal.noGuidance
|
||||
, error = InputErrorAndGuidanceInternal.noError
|
||||
, showPennant = False
|
||||
, hideLabel = False
|
||||
, containerCss = []
|
||||
, custom = []
|
||||
, onSelect = Nothing
|
||||
, premiumMsg = Nothing
|
||||
, disclosedContent = []
|
||||
}
|
||||
|
||||
|
||||
applyConfig : List (Attribute value msg) -> Config value msg -> Config value msg
|
||||
applyConfig attributes beginningConfig =
|
||||
List.foldl (\(Attribute update) config -> update config)
|
||||
beginningConfig
|
||||
attributes
|
||||
|
||||
|
||||
maybeAttr : (a -> Html.Attribute msg) -> Maybe a -> Html.Attribute msg
|
||||
maybeAttr attr maybeValue =
|
||||
maybeValue
|
||||
|> Maybe.map attr
|
||||
|> Maybe.withDefault Extra.none
|
||||
|
||||
|
||||
{-| View a single radio button.
|
||||
-}
|
||||
view :
|
||||
{ label : String
|
||||
, name : String
|
||||
, value : value
|
||||
, valueToString : value -> String
|
||||
, selectedValue : Maybe value
|
||||
}
|
||||
-> List (Attribute value msg)
|
||||
-> Html msg
|
||||
view { label, name, value, valueToString, selectedValue } attributes =
|
||||
let
|
||||
config =
|
||||
applyConfig attributes emptyConfig
|
||||
|
||||
stringValue =
|
||||
valueToString value
|
||||
|
||||
idValue =
|
||||
case config.id of
|
||||
Just specificId ->
|
||||
specificId
|
||||
|
||||
Nothing ->
|
||||
name ++ "-" ++ dasherize (toLower stringValue)
|
||||
|
||||
isChecked =
|
||||
selectedValue == Just value
|
||||
|
||||
isLocked =
|
||||
Maybe.map2 PremiumLevel.allowedFor config.contentPremiumLevel config.teacherPremiumLevel
|
||||
|> Maybe.withDefault True
|
||||
|> not
|
||||
|
||||
( disclosureId, disclosureElement ) =
|
||||
case ( config.disclosedContent, isChecked ) of
|
||||
( [], _ ) ->
|
||||
( Nothing, text "" )
|
||||
|
||||
( _, False ) ->
|
||||
( Nothing, text "" )
|
||||
|
||||
( (_ :: _) as childNodes, True ) ->
|
||||
( Just (idValue ++ "-disclosure-content")
|
||||
, span [ Attributes.id (idValue ++ "-disclosure-content") ]
|
||||
childNodes
|
||||
)
|
||||
|
||||
isInError =
|
||||
InputErrorAndGuidanceInternal.getIsInError config.error
|
||||
|
||||
errorMessage_ =
|
||||
InputErrorAndGuidanceInternal.getErrorMessage config.error
|
||||
in
|
||||
Html.span
|
||||
[ Attributes.id (idValue ++ "-container")
|
||||
, classList [ ( "Nri-RadioButton-PremiumClass", config.showPennant ) ]
|
||||
, css
|
||||
[ position relative
|
||||
, marginLeft (px -4)
|
||||
, display inlineBlock
|
||||
, Css.height (px 34)
|
||||
, pseudoClass "focus-within"
|
||||
[ Css.Global.descendants
|
||||
[ Css.Global.class "Nri-RadioButton-RadioButtonIcon"
|
||||
[ borderColor (rgb 0 95 204)
|
||||
]
|
||||
]
|
||||
]
|
||||
, Css.batch config.containerCss
|
||||
]
|
||||
]
|
||||
[ radio name
|
||||
stringValue
|
||||
isChecked
|
||||
([ Attributes.id idValue
|
||||
, Widget.disabled (isLocked || config.isDisabled)
|
||||
, InputErrorAndGuidanceInternal.describedBy idValue config
|
||||
, case ( config.onSelect, config.isDisabled ) of
|
||||
( Just onSelect_, False ) ->
|
||||
onClick (onSelect_ value)
|
||||
|
||||
_ ->
|
||||
Extra.none
|
||||
, class "Nri-RadioButton-HiddenRadioInput"
|
||||
, maybeAttr Aria.controls disclosureId
|
||||
, css
|
||||
[ position absolute
|
||||
, top (px 4)
|
||||
, left (px 4)
|
||||
, opacity zero
|
||||
, pseudoClass "focus"
|
||||
[ Css.Global.adjacentSiblings
|
||||
[ Css.Global.everything
|
||||
[ Css.Global.descendants
|
||||
[ Css.Global.class "Nri-RadioButton-RadioButtonIcon"
|
||||
[ borderColor (rgb 0 95 204)
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
++ List.map (Attributes.map never) config.custom
|
||||
)
|
||||
, Html.label
|
||||
[ for idValue
|
||||
, classList
|
||||
[ ( "Nri-RadioButton-RadioButton", True )
|
||||
, ( "Nri-RadioButton-RadioButtonChecked", isChecked )
|
||||
]
|
||||
, css
|
||||
[ position relative
|
||||
, outline Css.none
|
||||
, margin zero
|
||||
, Fonts.baseFont
|
||||
, Css.batch
|
||||
(if config.isDisabled then
|
||||
[ color Colors.gray45
|
||||
, cursor notAllowed
|
||||
]
|
||||
|
||||
else if isInError then
|
||||
[ color Colors.purple
|
||||
, cursor pointer
|
||||
]
|
||||
|
||||
else
|
||||
[ color Colors.navy
|
||||
, cursor pointer
|
||||
]
|
||||
)
|
||||
, padding4 (px 6) zero (px 4) (px 40)
|
||||
, fontSize (px 15)
|
||||
, Css.property "font-weight" "600"
|
||||
, display inlineBlock
|
||||
, Css.property "transition" "all 0.4s ease"
|
||||
]
|
||||
]
|
||||
[ radioInputIcon
|
||||
{ isLocked = isLocked
|
||||
, isDisabled = config.isDisabled
|
||||
, isChecked = isChecked
|
||||
}
|
||||
, span
|
||||
[ css
|
||||
[ display inlineFlex
|
||||
, alignItems center
|
||||
, Css.height (px 20)
|
||||
]
|
||||
]
|
||||
[ Html.span
|
||||
[ css <|
|
||||
if config.hideLabel then
|
||||
[ Css.width (px 1)
|
||||
, overflow Css.hidden
|
||||
, margin (px -1)
|
||||
, padding (px 0)
|
||||
, border (px 0)
|
||||
, display inlineBlock
|
||||
, textIndent (px 1)
|
||||
]
|
||||
|
||||
else
|
||||
[]
|
||||
]
|
||||
[ Html.text label ]
|
||||
, case ( config.contentPremiumLevel, config.premiumMsg ) of
|
||||
( Nothing, _ ) ->
|
||||
text ""
|
||||
|
||||
( Just PremiumLevel.Free, _ ) ->
|
||||
text ""
|
||||
|
||||
( Just _, Just premiumMsg ) ->
|
||||
premiumPennant premiumMsg
|
||||
|
||||
_ ->
|
||||
text ""
|
||||
]
|
||||
]
|
||||
, disclosureElement
|
||||
, InputErrorAndGuidanceInternal.view idValue config
|
||||
]
|
||||
|
||||
|
||||
premiumPennant : msg -> Html msg
|
||||
premiumPennant onClick =
|
||||
ClickableSvg.button "Premium"
|
||||
Pennant.premiumFlag
|
||||
[ ClickableSvg.onClick onClick
|
||||
, ClickableSvg.exactWidth 26
|
||||
, ClickableSvg.exactHeight 24
|
||||
, ClickableSvg.css
|
||||
[ marginLeft (px 8)
|
||||
, verticalAlign middle
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
radioInputIcon :
|
||||
{ isChecked : Bool
|
||||
, isLocked : Bool
|
||||
, isDisabled : Bool
|
||||
}
|
||||
-> Html msg
|
||||
radioInputIcon config =
|
||||
let
|
||||
image =
|
||||
case ( config.isDisabled, config.isLocked, config.isChecked ) of
|
||||
( _, True, _ ) ->
|
||||
lockedSvg
|
||||
|
||||
( True, _, _ ) ->
|
||||
unselectedSvg
|
||||
|
||||
( _, False, True ) ->
|
||||
selectedSvg
|
||||
|
||||
( _, False, False ) ->
|
||||
unselectedSvg
|
||||
in
|
||||
div
|
||||
[ classList
|
||||
[ ( "Nri-RadioButton-RadioButtonIcon", True )
|
||||
, ( "Nri-RadioButton-RadioButtonDisabled", config.isDisabled )
|
||||
]
|
||||
, css
|
||||
[ Css.batch <|
|
||||
if config.isDisabled then
|
||||
[ opacity (num 0.4) ]
|
||||
|
||||
else
|
||||
[]
|
||||
, position absolute
|
||||
, left zero
|
||||
, top zero
|
||||
, Css.property "transition" ".3s all"
|
||||
, border3 (px 2) solid transparent
|
||||
, borderRadius (px 50)
|
||||
, padding (px 2)
|
||||
, displayFlex
|
||||
, justifyContent center
|
||||
, alignItems center
|
||||
]
|
||||
]
|
||||
[ image
|
||||
|> Nri.Ui.Svg.V1.withHeight (Css.px 26)
|
||||
|> Nri.Ui.Svg.V1.withWidth (Css.px 26)
|
||||
|> Nri.Ui.Svg.V1.toHtml
|
||||
]
|
||||
|
||||
|
||||
unselectedSvg : Svg
|
||||
unselectedSvg =
|
||||
Svg.svg [ SvgAttributes.viewBox "0 0 27 27" ]
|
||||
[ Svg.defs []
|
||||
[ Svg.rect [ SvgAttributes.id "unselected-path-1", SvgAttributes.x "0", SvgAttributes.y "0", SvgAttributes.width "27", SvgAttributes.height "27", SvgAttributes.rx "13.5" ] []
|
||||
, Svg.filter [ SvgAttributes.id "unselected-filter-2", SvgAttributes.x "-3.7%", SvgAttributes.y "-3.7%", SvgAttributes.width "107.4%", SvgAttributes.height "107.4%", SvgAttributes.filterUnits "objectBoundingBox" ] [ Svg.feOffset [ SvgAttributes.dx "0", SvgAttributes.dy "2", SvgAttributes.in_ "SourceAlpha", SvgAttributes.result "shadowOffsetInner1" ] [], Svg.feComposite [ SvgAttributes.in_ "shadowOffsetInner1", SvgAttributes.in2 "SourceAlpha", SvgAttributes.operator "arithmetic", SvgAttributes.k2 "-1", SvgAttributes.k3 "1", SvgAttributes.result "shadowInnerInner1" ] [], Svg.feColorMatrix [ SvgAttributes.values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0", SvgAttributes.in_ "shadowInnerInner1" ] [] ]
|
||||
]
|
||||
, Svg.g
|
||||
[ SvgAttributes.stroke "none"
|
||||
, SvgAttributes.strokeWidth "1"
|
||||
, SvgAttributes.fill "none"
|
||||
, SvgAttributes.fillRule "evenodd"
|
||||
]
|
||||
[ Svg.g []
|
||||
[ Svg.g []
|
||||
[ Svg.use
|
||||
[ SvgAttributes.fill "#EBEBEB"
|
||||
, SvgAttributes.fillRule "evenodd"
|
||||
, SvgAttributes.xlinkHref "#unselected-path-1"
|
||||
]
|
||||
[]
|
||||
, Svg.use
|
||||
[ SvgAttributes.fill "black"
|
||||
, SvgAttributes.fillOpacity "1"
|
||||
, SvgAttributes.filter "url(#unselected-filter-2)"
|
||||
, SvgAttributes.xlinkHref "#unselected-path-1"
|
||||
]
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|> Nri.Ui.Svg.V1.fromHtml
|
||||
|
||||
|
||||
selectedSvg : Svg
|
||||
selectedSvg =
|
||||
Svg.svg [ SvgAttributes.viewBox "0 0 27 27" ]
|
||||
[ Svg.defs []
|
||||
[ Svg.rect [ SvgAttributes.id "selected-path-1", SvgAttributes.x "0", SvgAttributes.y "0", SvgAttributes.width "27", SvgAttributes.height "27", SvgAttributes.rx "13.5" ] []
|
||||
, Svg.filter
|
||||
[ SvgAttributes.id "selected-filter-2", SvgAttributes.x "-3.7%", SvgAttributes.y "-3.7%", SvgAttributes.width "107.4%", SvgAttributes.height "107.4%", SvgAttributes.filterUnits "objectBoundingBox" ]
|
||||
[ Svg.feOffset [ SvgAttributes.dx "0", SvgAttributes.dy "2", SvgAttributes.in_ "SourceAlpha", SvgAttributes.result "shadowOffsetInner1" ] [], Svg.feComposite [ SvgAttributes.in_ "shadowOffsetInner1", SvgAttributes.in2 "SourceAlpha", SvgAttributes.operator "arithmetic", SvgAttributes.k2 "-1", SvgAttributes.k3 "1", SvgAttributes.result "shadowInnerInner1" ] [], Svg.feColorMatrix [ SvgAttributes.values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0", SvgAttributes.in_ "shadowInnerInner1" ] [] ]
|
||||
]
|
||||
, Svg.g
|
||||
[ SvgAttributes.stroke "none"
|
||||
, SvgAttributes.strokeWidth "1"
|
||||
, SvgAttributes.fill "none"
|
||||
, SvgAttributes.fillRule "evenodd"
|
||||
]
|
||||
[ Svg.g []
|
||||
[ Svg.g []
|
||||
[ Svg.use
|
||||
[ SvgAttributes.fill "#D4F0FF"
|
||||
, SvgAttributes.fillRule "evenodd"
|
||||
, SvgAttributes.xlinkHref "#selected-path-1"
|
||||
]
|
||||
[]
|
||||
, Svg.use
|
||||
[ SvgAttributes.fill "black"
|
||||
, SvgAttributes.fillOpacity "1"
|
||||
, SvgAttributes.filter "url(#selected-filter-2)"
|
||||
, SvgAttributes.xlinkHref "#selected-path-1"
|
||||
]
|
||||
[]
|
||||
]
|
||||
, Svg.circle
|
||||
[ SvgAttributes.fill "#146AFF"
|
||||
, SvgAttributes.cx "13.5"
|
||||
, SvgAttributes.cy "13.5"
|
||||
, SvgAttributes.r "6.3"
|
||||
]
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
|> Nri.Ui.Svg.V1.fromHtml
|
||||
|
||||
|
||||
lockedSvg : Svg
|
||||
lockedSvg =
|
||||
Svg.svg [ SvgAttributes.viewBox "0 0 30 30" ]
|
||||
[ Svg.defs []
|
||||
[ Svg.rect [ SvgAttributes.id "locked-path-1", SvgAttributes.x "0", SvgAttributes.y "0", SvgAttributes.width "30", SvgAttributes.height "30", SvgAttributes.rx "15" ] []
|
||||
, Svg.filter [ SvgAttributes.id "locked-filter-2", SvgAttributes.x "-3.3%", SvgAttributes.y "-3.3%", SvgAttributes.width "106.7%", SvgAttributes.height "106.7%", SvgAttributes.filterUnits "objectBoundingBox" ] [ Svg.feOffset [ SvgAttributes.dx "0", SvgAttributes.dy "2", SvgAttributes.in_ "SourceAlpha", SvgAttributes.result "shadowOffsetInner1" ] [], Svg.feComposite [ SvgAttributes.in_ "shadowOffsetInner1", SvgAttributes.in2 "SourceAlpha", SvgAttributes.operator "arithmetic", SvgAttributes.k2 "-1", SvgAttributes.k3 "1", SvgAttributes.result "shadowInnerInner1" ] [], Svg.feColorMatrix [ SvgAttributes.values "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0", SvgAttributes.in_ "shadowInnerInner1" ] [] ]
|
||||
]
|
||||
, Svg.g
|
||||
[ SvgAttributes.stroke "none"
|
||||
, SvgAttributes.strokeWidth "1"
|
||||
, SvgAttributes.fill "none"
|
||||
, SvgAttributes.fillRule "evenodd"
|
||||
]
|
||||
[ Svg.g []
|
||||
[ Svg.use
|
||||
[ SvgAttributes.fill "#EBEBEB"
|
||||
, SvgAttributes.fillRule "evenodd"
|
||||
, SvgAttributes.xlinkHref "#locked-path-1"
|
||||
]
|
||||
[]
|
||||
, Svg.use
|
||||
[ SvgAttributes.fill "black"
|
||||
, SvgAttributes.fillOpacity "1"
|
||||
, SvgAttributes.filter "url(#locked-filter-2)"
|
||||
, SvgAttributes.xlinkHref "#locked-path-1"
|
||||
]
|
||||
[]
|
||||
]
|
||||
, Svg.g
|
||||
[ SvgAttributes.transform "translate(8.000000, 5.000000)"
|
||||
]
|
||||
[ Svg.path
|
||||
[ SvgAttributes.d "M11.7991616,9.36211885 L11.7991616,5.99470414 C11.7991616,3.24052783 9.64616757,1 7.00011784,1 C4.35359674,1 2.20083837,3.24052783 2.20083837,5.99470414 L2.20083837,9.36211885 L1.51499133,9.36211885 C0.678540765,9.36211885 -6.21724894e-14,10.0675883 -6.21724894e-14,10.9381415 L-6.21724894e-14,18.9239773 C-6.21724894e-14,19.7945305 0.678540765,20.5 1.51499133,20.5 L12.48548,20.5 C13.3219306,20.5 14,19.7945305 14,18.9239773 L14,10.9383868 C14,10.0678336 13.3219306,9.36211885 12.48548,9.36211885 L11.7991616,9.36211885 Z M7.46324136,15.4263108 L7.46324136,17.2991408 C7.46324136,17.5657769 7.25560176,17.7816368 7.00011784,17.7816368 C6.74416256,17.7816368 6.53652295,17.5657769 6.53652295,17.2991408 L6.53652295,15.4263108 C6.01259238,15.228848 5.63761553,14.7080859 5.63761553,14.0943569 C5.63761553,13.3116195 6.24757159,12.6763045 7.00011784,12.6763045 C7.75195704,12.6763045 8.36285584,13.3116195 8.36285584,14.0943569 C8.36285584,14.7088218 7.98717193,15.2295839 7.46324136,15.4263108 L7.46324136,15.4263108 Z M9.98178482,9.36211885 L4.01821518,9.36211885 L4.01821518,5.99470414 C4.01821518,4.2835237 5.35597044,2.89122723 7.00011784,2.89122723 C8.64402956,2.89122723 9.98178482,4.2835237 9.98178482,5.99470414 L9.98178482,9.36211885 L9.98178482,9.36211885 Z"
|
||||
, SvgAttributes.fill "#E68800"
|
||||
]
|
||||
[]
|
||||
, Svg.path
|
||||
[ SvgAttributes.d "M11.7991616,8.14770554 L11.7991616,4.8666348 C11.7991616,2.18307839 9.64616757,-7.10542736e-15 7.00011784,-7.10542736e-15 C4.35359674,-7.10542736e-15 2.20083837,2.18307839 2.20083837,4.8666348 L2.20083837,8.14770554 L1.51499133,8.14770554 C0.678540765,8.14770554 -6.21724894e-14,8.83508604 -6.21724894e-14,9.6833174 L-6.21724894e-14,17.4643881 C-6.21724894e-14,18.3126195 0.678540765,19 1.51499133,19 L12.48548,19 C13.3219306,19 14,18.3126195 14,17.4643881 L14,9.68355641 C14,8.83532505 13.3219306,8.14770554 12.48548,8.14770554 L11.7991616,8.14770554 Z M7.46324136,14.0564054 L7.46324136,15.8812141 C7.46324136,16.1410134 7.25560176,16.3513384 7.00011784,16.3513384 C6.74416256,16.3513384 6.53652295,16.1410134 6.53652295,15.8812141 L6.53652295,14.0564054 C6.01259238,13.8640057 5.63761553,13.3565966 5.63761553,12.7586042 C5.63761553,11.9959369 6.24757159,11.376912 7.00011784,11.376912 C7.75195704,11.376912 8.36285584,11.9959369 8.36285584,12.7586042 C8.36285584,13.3573136 7.98717193,13.8647228 7.46324136,14.0564054 L7.46324136,14.0564054 Z M9.98178482,8.14770554 L4.01821518,8.14770554 L4.01821518,4.8666348 C4.01821518,3.19933078 5.35597044,1.84273423 7.00011784,1.84273423 C8.64402956,1.84273423 9.98178482,3.19933078 9.98178482,4.8666348 L9.98178482,8.14770554 L9.98178482,8.14770554 Z"
|
||||
, SvgAttributes.fill "#FEC709"
|
||||
]
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
|> Nri.Ui.Svg.V1.fromHtml
|
@ -1,9 +1,18 @@
|
||||
module CommonControls exposing (exampleHtml, httpError, quickBrownFox, romeoAndJulietQuotation)
|
||||
module CommonControls exposing (exampleHtml, httpError, premiumLevel, quickBrownFox, romeoAndJulietQuotation)
|
||||
|
||||
import Debug.Control as Control exposing (Control)
|
||||
import Html.Styled as Html exposing (Html)
|
||||
import Html.Styled.Attributes as Attributes
|
||||
import Http
|
||||
import Nri.Ui.Data.PremiumLevel exposing (PremiumLevel(..))
|
||||
|
||||
|
||||
premiumLevel : Control ( String, PremiumLevel )
|
||||
premiumLevel =
|
||||
Control.choice
|
||||
[ ( "Free", Control.value ( "Free", Free ) )
|
||||
, ( "PremiumWithWriting", Control.value ( "PremiumWithWriting", PremiumWithWriting ) )
|
||||
]
|
||||
|
||||
|
||||
httpError : Control Http.Error
|
||||
|
@ -12,18 +12,19 @@ module Examples.RadioButton exposing
|
||||
|
||||
import Browser.Dom as Dom
|
||||
import Category exposing (Category(..))
|
||||
import Css exposing (..)
|
||||
import CommonControls exposing (premiumLevel)
|
||||
import Css
|
||||
import Debug.Control as Control exposing (Control)
|
||||
import Dict exposing (Dict)
|
||||
import Debug.Control.Extra as ControlExtra
|
||||
import Example exposing (Example)
|
||||
import Html.Styled as Html exposing (..)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import Html.Styled.Attributes as Attributes exposing (css)
|
||||
import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
import Nri.Ui.Button.V10 as Button
|
||||
import Nri.Ui.Data.PremiumLevel as PremiumLevel exposing (PremiumLevel)
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Modal.V11 as Modal
|
||||
import Nri.Ui.RadioButton.V2 as RadioButton
|
||||
import Nri.Ui.RadioButton.V3 as RadioButton
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
import Task
|
||||
|
||||
@ -32,7 +33,7 @@ import Task
|
||||
example : Example State Msg
|
||||
example =
|
||||
{ name = "RadioButton"
|
||||
, version = 2
|
||||
, version = 3
|
||||
, state = init
|
||||
, update = update
|
||||
, subscriptions = subscriptions
|
||||
@ -55,16 +56,21 @@ example =
|
||||
|
||||
{-| -}
|
||||
view : State -> List (Html Msg)
|
||||
view model =
|
||||
[ Heading.h3 [] [ Html.text "RadioButton" ]
|
||||
, Heading.h4 [] [ Html.text "view" ]
|
||||
, viewVanilla model
|
||||
, Heading.h4 [] [ Html.text "premium" ]
|
||||
, viewPremium model
|
||||
view state =
|
||||
let
|
||||
selectionSettings =
|
||||
Control.currentValue state.selectionSettings
|
||||
in
|
||||
[ div
|
||||
[ css [ Css.displayFlex, Css.justifyContent Css.spaceBetween ] ]
|
||||
[ Control.view SetSelectionSettings state.selectionSettings |> fromUnstyled
|
||||
, viewExamples selectionSettings state.selectedValue
|
||||
, viewExamplesCode selectionSettings state.selectedValue
|
||||
]
|
||||
, Modal.view
|
||||
{ title = "Go Premium!"
|
||||
, wrapMsg = ModalMsg
|
||||
, content = [ Text.mediumBody [ Text.plaintext "Often, we'll launch a modal showing the benefits of premium when a locked radio button is clicked." ] ]
|
||||
, content = [ Text.mediumBody [ Text.plaintext "Often, we'll launch a modal showing the benefits of premium when a Premium pennant is clicked." ] ]
|
||||
, footer =
|
||||
[ Button.button "Okay"
|
||||
[ Button.modal
|
||||
@ -79,112 +85,91 @@ view model =
|
||||
}
|
||||
}
|
||||
[ Modal.closeButton ]
|
||||
model.modal
|
||||
state.modal
|
||||
]
|
||||
|
||||
|
||||
viewVanilla : State -> Html Msg
|
||||
viewVanilla state =
|
||||
div []
|
||||
[ RadioButton.view
|
||||
{ label = "Cats"
|
||||
, value = "Cats"
|
||||
, name = "radio-button-examples"
|
||||
, selectedValue = state.selectedValue
|
||||
, onSelect = Select
|
||||
, valueToString = identity
|
||||
}
|
||||
, RadioButton.view
|
||||
{ label = "Dogs"
|
||||
, value = "Dogs"
|
||||
, name = "radio-button-examples"
|
||||
, selectedValue = state.selectedValue
|
||||
, onSelect = Select
|
||||
, valueToString = identity
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
viewPremium : State -> Html Msg
|
||||
viewPremium state =
|
||||
viewExamplesCode : SelectionSettings -> Maybe Selection -> Html Msg
|
||||
viewExamplesCode selectionSettings selectedValue =
|
||||
let
|
||||
premiumConfig =
|
||||
Control.currentValue state.premiumControl
|
||||
selectedValueString =
|
||||
case selectedValue of
|
||||
Just value ->
|
||||
"Just " ++ selectionToString value
|
||||
|
||||
Nothing ->
|
||||
"Nothing"
|
||||
|
||||
toExampleCode ( kind, settings ) =
|
||||
"RadioButton.view"
|
||||
++ ("\n\t{ label = " ++ selectionToString kind)
|
||||
++ "\n\t, name = \"pets\""
|
||||
++ ("\n\t, value = " ++ selectionToString kind)
|
||||
++ ("\n\t, selectedValue = " ++ selectedValueString)
|
||||
++ "\n\t, valueToString = toString"
|
||||
++ "\n\t}\n\t[ "
|
||||
++ String.join "\n\t, " (List.map Tuple.first settings)
|
||||
++ "\n\t] "
|
||||
in
|
||||
div []
|
||||
[ Heading.h4 [] [ Html.text "Premium Radio Buttons" ]
|
||||
, Html.div [ css [ Css.margin (Css.px 8) ] ]
|
||||
[ Control.view SetPremiumControl state.premiumControl
|
||||
|> Html.fromUnstyled
|
||||
Html.code
|
||||
[ css
|
||||
[ Css.display Css.block
|
||||
, Css.marginLeft (Css.px 20)
|
||||
]
|
||||
, RadioButton.premium
|
||||
{ label = "Hedgehog (Free)"
|
||||
, value = "Hedgehogs"
|
||||
, name = "radio-button-examples"
|
||||
, selectedValue = state.selectedValue
|
||||
, teacherPremiumLevel = premiumConfig.teacherPremiumLevel
|
||||
, contentPremiumLevel = PremiumLevel.Free
|
||||
, onSelect = Select
|
||||
|
||||
-- TODO:
|
||||
-- the next version of the RadioComponent will handle focus correctly,
|
||||
-- including re-capturing the focus when the modal closes.
|
||||
-- While we could change premiumMsg to be String -> msg now,
|
||||
-- and use the correct id, there's not much point in doing
|
||||
-- so yet since the radio doesn't handle focus correctly.
|
||||
, premiumMsg = OpenModal "hedgehogs-free"
|
||||
, valueToString = identity
|
||||
, showPennant = premiumConfig.showPennant
|
||||
, isDisabled = False
|
||||
}
|
||||
, RadioButton.premium
|
||||
{ label = "Hedgehodge (Premium)"
|
||||
, value = "Hedgehodges"
|
||||
, name = "radio-button-examples"
|
||||
, selectedValue = state.selectedValue
|
||||
, teacherPremiumLevel = premiumConfig.teacherPremiumLevel
|
||||
, contentPremiumLevel = PremiumLevel.PremiumWithWriting
|
||||
, onSelect = Select
|
||||
|
||||
-- TODO:
|
||||
-- the next version of the RadioComponent will handle focus correctly,
|
||||
-- including re-capturing the focus when the modal closes.
|
||||
-- While we could change premiumMsg to be String -> msg now,
|
||||
-- and use the correct id, there's not much point in doing
|
||||
-- so yet since the radio doesn't handle focus correctly.
|
||||
, premiumMsg = OpenModal "hedgehogs-premium"
|
||||
, valueToString = identity
|
||||
, showPennant = premiumConfig.showPennant
|
||||
, isDisabled = False
|
||||
}
|
||||
, RadioButton.premium
|
||||
{ label = "Disabled"
|
||||
, value = "Disabled"
|
||||
, name = "radio-button-examples"
|
||||
, selectedValue = state.selectedValue
|
||||
, teacherPremiumLevel = premiumConfig.teacherPremiumLevel
|
||||
, contentPremiumLevel = PremiumLevel.PremiumWithWriting
|
||||
, onSelect = Select
|
||||
|
||||
-- TODO:
|
||||
-- the next version of the RadioComponent will handle focus correctly,
|
||||
-- including re-capturing the focus when the modal closes.
|
||||
-- While we could change premiumMsg to be String -> msg now,
|
||||
-- and use the correct id, there's not much point in doing
|
||||
-- so yet since the radio doesn't handle focus correctly.
|
||||
, premiumMsg = OpenModal "hedgehogs-premium"
|
||||
, valueToString = identity
|
||||
, showPennant = premiumConfig.showPennant
|
||||
, isDisabled = True
|
||||
}
|
||||
]
|
||||
[ Html.pre []
|
||||
[ text
|
||||
(" " ++ String.join "\n, " (List.map toExampleCode (examples selectionSettings)))
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
viewExamples : SelectionSettings -> Maybe Selection -> Html Msg
|
||||
viewExamples selectionSettings selectedValue =
|
||||
let
|
||||
viewExample_ ( kind, settings ) =
|
||||
RadioButton.view
|
||||
{ label = selectionToString kind
|
||||
, name = "pets"
|
||||
, value = kind
|
||||
, selectedValue = selectedValue
|
||||
, valueToString = selectionToString
|
||||
}
|
||||
(RadioButton.onSelect Select :: List.map Tuple.second settings)
|
||||
in
|
||||
div [ css [ Css.flexBasis (Css.px 300) ] ]
|
||||
(List.map viewExample_ (examples selectionSettings))
|
||||
|
||||
|
||||
examples :
|
||||
SelectionSettings
|
||||
-> List ( Selection, List ( String, RadioButton.Attribute Selection Msg ) )
|
||||
examples selectionSettings =
|
||||
[ ( Dogs, selectionSettings.dogs )
|
||||
, ( Cats, selectionSettings.cats )
|
||||
]
|
||||
|
||||
|
||||
type Selection
|
||||
= Dogs
|
||||
| Cats
|
||||
|
||||
|
||||
selectionToString : Selection -> String
|
||||
selectionToString selection =
|
||||
case selection of
|
||||
Dogs ->
|
||||
"Dogs"
|
||||
|
||||
Cats ->
|
||||
"Cats"
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias State =
|
||||
{ selectedValue : Maybe String
|
||||
{ selectedValue : Maybe Selection
|
||||
, modal : Modal.Model
|
||||
, premiumControl : Control PremiumConfig
|
||||
, selectionSettings : Control SelectionSettings
|
||||
}
|
||||
|
||||
|
||||
@ -193,34 +178,136 @@ init : State
|
||||
init =
|
||||
{ selectedValue = Nothing
|
||||
, modal = Modal.init
|
||||
, premiumControl = initPremiumControls
|
||||
, selectionSettings = initSelectionSettings
|
||||
}
|
||||
|
||||
|
||||
type alias PremiumConfig =
|
||||
{ teacherPremiumLevel : PremiumLevel
|
||||
, showPennant : Bool
|
||||
type alias SelectionSettings =
|
||||
{ dogs : List ( String, RadioButton.Attribute Selection Msg )
|
||||
, cats : List ( String, RadioButton.Attribute Selection Msg )
|
||||
}
|
||||
|
||||
|
||||
initPremiumControls : Control PremiumConfig
|
||||
initPremiumControls =
|
||||
Control.record PremiumConfig
|
||||
|> Control.field "teacherPremiumLevel"
|
||||
initSelectionSettings : Control SelectionSettings
|
||||
initSelectionSettings =
|
||||
Control.record SelectionSettings
|
||||
|> Control.field "Dogs" controlAttributes
|
||||
|> Control.field "Cats" controlAttributes
|
||||
|
||||
|
||||
controlAttributes : Control (List ( String, RadioButton.Attribute Selection Msg ))
|
||||
controlAttributes =
|
||||
ControlExtra.list
|
||||
|> ControlExtra.optionalListItem "visibility" labelVisibility
|
||||
|> ControlExtra.optionalListItem "status" disabledOrEnabled
|
||||
|> ControlExtra.optionalListItem "showPennant" showPennant
|
||||
|> ControlExtra.optionalListItem "premium"
|
||||
-- TODO: allow the teacher premium level to vary as well:
|
||||
(Control.map
|
||||
(\( contentLevel, clevel ) ->
|
||||
( "RadioButton.premium { teacherPremiumLevel = PremiumLevel.Premium, contentPremiumLevel = "
|
||||
++ contentLevel
|
||||
++ "}"
|
||||
, RadioButton.premium
|
||||
{ teacherPremiumLevel = PremiumLevel.Premium
|
||||
, contentPremiumLevel = clevel
|
||||
}
|
||||
)
|
||||
)
|
||||
premiumLevel
|
||||
)
|
||||
|> ControlExtra.optionalListItem "containerCss"
|
||||
(Control.choice
|
||||
[ ( "Free", Control.value PremiumLevel.Free )
|
||||
, ( "Premium", Control.value PremiumLevel.PremiumWithWriting )
|
||||
[ ( "100% width"
|
||||
, Control.value
|
||||
( "RadioButton.containerCss [ Css.width (Css.pct 100) ]"
|
||||
, RadioButton.containerCss [ Css.width (Css.pct 100) ]
|
||||
)
|
||||
)
|
||||
, ( "10px right margin"
|
||||
, Control.value
|
||||
( "RadioButton.containerCss [ Css.marginRight (Css.px 10) ]"
|
||||
, RadioButton.containerCss [ Css.marginRight (Css.px 10) ]
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
|> Control.field "showPennant" (Control.bool False)
|
||||
|> ControlExtra.optionalListItem "disclosure" controlDisclosure
|
||||
|> ControlExtra.optionalListItem "errorIf"
|
||||
(Control.map
|
||||
(\inError ->
|
||||
( "RadioButton.errorIf " ++ Debug.toString inError
|
||||
, RadioButton.errorIf inError
|
||||
)
|
||||
)
|
||||
<|
|
||||
Control.bool True
|
||||
)
|
||||
|> ControlExtra.optionalListItem "errorMessage"
|
||||
(Control.map
|
||||
(\message ->
|
||||
( "RadioButton.errorMessage (Just \"" ++ message ++ "\")"
|
||||
, RadioButton.errorMessage (Just message)
|
||||
)
|
||||
)
|
||||
<|
|
||||
Control.string "The statement must be true."
|
||||
)
|
||||
|> ControlExtra.optionalListItem "guidance"
|
||||
(Control.map
|
||||
(\content ->
|
||||
( "RadioButton.guidance \"" ++ content ++ "\""
|
||||
, RadioButton.guidance content
|
||||
)
|
||||
)
|
||||
<|
|
||||
Control.string "The statement must be true."
|
||||
)
|
||||
|
||||
|
||||
labelVisibility : Control ( String, RadioButton.Attribute Selection Msg )
|
||||
labelVisibility =
|
||||
Control.choice
|
||||
[ ( "hiddenLabel", Control.value ( "RadioButton.hiddenLabel", RadioButton.hiddenLabel ) )
|
||||
, ( "visibleLabel", Control.value ( "RadioButton.visibleLabel", RadioButton.visibleLabel ) )
|
||||
]
|
||||
|
||||
|
||||
disabledOrEnabled : Control ( String, RadioButton.Attribute Selection Msg )
|
||||
disabledOrEnabled =
|
||||
Control.choice
|
||||
[ ( "disabled", Control.value ( "RadioButton.disabled", RadioButton.disabled ) )
|
||||
, ( "enabled", Control.value ( "RadioButton.enabled", RadioButton.enabled ) )
|
||||
]
|
||||
|
||||
|
||||
showPennant : Control ( String, RadioButton.Attribute Selection Msg )
|
||||
showPennant =
|
||||
Control.value
|
||||
( "RadioButton.showPennant OpenPremiumModal"
|
||||
, RadioButton.showPennant (OpenModal "dogs")
|
||||
)
|
||||
|
||||
|
||||
controlDisclosure : Control ( String, RadioButton.Attribute Selection Msg )
|
||||
controlDisclosure =
|
||||
Control.map
|
||||
(\content ->
|
||||
( "RadioButton.disclosure [ Text.smallBody [ Text.plaintext \""
|
||||
++ content
|
||||
++ "\" ]"
|
||||
, RadioButton.disclosure [ Text.smallBody [ Text.plaintext content ] ]
|
||||
)
|
||||
)
|
||||
(Control.string "These pets occupy themselves.")
|
||||
|
||||
|
||||
type Msg
|
||||
= OpenModal String
|
||||
| ModalMsg Modal.Msg
|
||||
| CloseModal
|
||||
| Select String
|
||||
| SetPremiumControl (Control PremiumConfig)
|
||||
| Select Selection
|
||||
| SetSelectionSettings (Control SelectionSettings)
|
||||
| Focus String
|
||||
| Focused (Result Dom.Error ())
|
||||
|
||||
@ -258,8 +345,10 @@ update msg model =
|
||||
Select value ->
|
||||
( { model | selectedValue = Just value }, Cmd.none )
|
||||
|
||||
SetPremiumControl premiumControl ->
|
||||
( { model | premiumControl = premiumControl }, Cmd.none )
|
||||
SetSelectionSettings selectionSettings ->
|
||||
( { model | selectionSettings = selectionSettings }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
Focus focus ->
|
||||
( model, Task.attempt Focused (Dom.focus focus) )
|
||||
|
@ -40,6 +40,7 @@
|
||||
"Nri.Ui.Pennant.V2",
|
||||
"Nri.Ui.PremiumCheckbox.V6",
|
||||
"Nri.Ui.RadioButton.V2",
|
||||
"Nri.Ui.RadioButton.V3",
|
||||
"Nri.Ui.SegmentedControl.V14",
|
||||
"Nri.Ui.Select.V8",
|
||||
"Nri.Ui.Slide.V1",
|
||||
|
Loading…
Reference in New Issue
Block a user