Update modal to take advantage of the new button API

This commit is contained in:
Tessa Kelly 2019-07-25 22:14:26 -07:00
parent 0c6e191a1d
commit 1fcca16f12
2 changed files with 105 additions and 199 deletions

View File

@ -1,10 +1,10 @@
module Nri.Ui.Modal.V6 exposing
( Model, init
, Msg, update, subscriptions
, open, close
, info, warning, FocusableElementAttrs
, viewContent, viewFooter
, launchButton, closeButton
, primaryButton, secondaryButton, dangerButton
, closeButton
)
{-| Changes from V4:
@ -15,6 +15,7 @@ module Nri.Ui.Modal.V6 exposing
These changes have required major API changes. Be sure to wire up subscriptions!
import Html.Styled exposing (..)
import Nri.Ui.Button.V9 as Button
import Nri.Ui.Modal.V6 as Modal
view : Modal.State -> Html Msg
@ -27,7 +28,11 @@ These changes have required major API changes. Be sure to wire up subscriptions!
div []
[ Modal.viewContent [ text "Content goes here!" ]
, Modal.viewFooter
[ Modal.primaryButton DoSomething "Continue" onlyFocusableElement
[ Button.button "Continue"
[ Button.primary
, Button.onClick DoSomthing
, Button.custom onlyFocusableElement
]
, text "`onlyFocusableElement` will trap the focus on the 'Continue' button."
]
]
@ -44,6 +49,8 @@ These changes have required major API changes. Be sure to wire up subscriptions!
@docs Model, init
@docs Msg, update, subscriptions
@docs open, close
## Views
@ -58,10 +65,9 @@ These changes have required major API changes. Be sure to wire up subscriptions!
@docs viewContent, viewFooter
### Buttons
## X icon
@docs launchButton, closeButton
@docs primaryButton, secondaryButton, dangerButton
@docs closeButton
-}
@ -114,49 +120,77 @@ update config msg model =
Modal.update config msg model
{-| -}
close : Msg
close =
Modal.close
{-| Pass the id of the element that focus should return to when the modal closes.
-}
open : String -> Msg
open =
Modal.open
{-| -}
type alias FocusableElementAttrs msg =
{ onlyFocusableElement : List (Root.Attribute msg)
, firstFocusableElement : List (Root.Attribute msg)
, lastFocusableElement : List (Root.Attribute msg)
{ onlyFocusableElement : List (Attribute msg)
, firstFocusableElement : List (Attribute msg)
, lastFocusableElement : List (Attribute msg)
}
{-| -}
info :
{ title : { visibleTitle : Bool, title : String }
{ visibleTitle : Bool
, title : String
, content : FocusableElementAttrs msg -> Html msg
, wrapMsg : Msg -> msg
}
-> Model
-> Html msg
info config model =
Modal.view
{ overlayColor = toOverlayColor Colors.navy
, wrapMsg = config.wrapMsg
, modalAttributes = modalStyles
, title = viewTitle Colors.navy config.title
, content = config.content >> toUnstyled
}
model
|> fromUnstyled
view { overlayColor = Colors.navy, titleColor = Colors.navy } config model
{-| -}
warning :
{ title : { visibleTitle : Bool, title : String }
{ visibleTitle : Bool
, title : String
, content : FocusableElementAttrs msg -> Html msg
, wrapMsg : Msg -> msg
}
-> Model
-> Html msg
warning config model =
view { overlayColor = Colors.gray20, titleColor = Colors.red } config model
view :
{ overlayColor : Css.Color, titleColor : Css.Color }
->
{ visibleTitle : Bool
, title : String
, content : FocusableElementAttrs msg -> Html msg
, wrapMsg : Msg -> msg
}
-> Model
-> Html msg
view { overlayColor, titleColor } config model =
Modal.view
{ overlayColor = toOverlayColor Colors.gray20
{ overlayColor = toOverlayColor overlayColor
, wrapMsg = config.wrapMsg
, modalAttributes = modalStyles
, title = viewTitle Colors.red config.title
, content = config.content >> toUnstyled
, title = viewTitle titleColor { title = config.title, visibleTitle = config.visibleTitle }
, content =
\{ onlyFocusableElement, firstFocusableElement, lastFocusableElement } ->
{ onlyFocusableElement = List.map Html.Styled.Attributes.fromUnstyled onlyFocusableElement
, firstFocusableElement = List.map Html.Styled.Attributes.fromUnstyled firstFocusableElement
, lastFocusableElement = List.map Html.Styled.Attributes.fromUnstyled lastFocusableElement
}
|> config.content
|> toUnstyled
}
model
|> fromUnstyled
@ -238,18 +272,7 @@ viewFooter =
{-| -}
launchButton : (Msg -> msg) -> List Css.Style -> String -> Html msg
launchButton wrapMsg styles label =
button
(css styles
:: List.map Html.Styled.Attributes.fromUnstyled
(Modal.openOnClick wrapMsg (String.replace " " "-" label))
)
[ text label ]
{-| -}
closeButton : (Msg -> msg) -> List (Root.Attribute msg) -> Html msg
closeButton : (Msg -> msg) -> List (Attribute msg) -> Html msg
closeButton wrapMsg focusableElementAttrs =
Nri.Ui.styled button
"close-button-container"
@ -267,155 +290,7 @@ closeButton wrapMsg focusableElementAttrs =
]
(Widget.label "Close modal"
:: Html.Styled.Attributes.map wrapMsg (onClick Modal.close)
:: List.map Html.Styled.Attributes.fromUnstyled focusableElementAttrs
:: focusableElementAttrs
)
[ Nri.Ui.Svg.V1.toHtml Nri.Ui.SpriteSheet.xSvg
]
{-| -}
primaryButton : msg -> String -> List (Root.Attribute msg) -> Html msg
primaryButton msg label focusableElementAttrs =
Nri.Ui.styled button
"modal__primary-button"
[ buttonStyle, colorStyle PrimaryColors, sizeStyle ]
(onClick msg :: List.map Html.Styled.Attributes.fromUnstyled focusableElementAttrs)
[ text label ]
{-| -}
secondaryButton : msg -> String -> List (Root.Attribute msg) -> Html msg
secondaryButton msg label focusableElementAttrs =
Nri.Ui.styled button
"modal__secondary-button"
[ buttonStyle
, colorStyle SecondaryColors
, Css.fontSize (Css.px 20)
, Css.marginTop (Css.px 30)
]
(onClick msg :: List.map Html.Styled.Attributes.fromUnstyled focusableElementAttrs)
[ text label ]
{-| -}
dangerButton : msg -> String -> List (Root.Attribute msg) -> Html msg
dangerButton msg label focusableElementAttrs =
Nri.Ui.styled button
"modal__warning-button"
[ buttonStyle, colorStyle DangerColors, sizeStyle ]
(onClick msg :: List.map Html.Styled.Attributes.fromUnstyled focusableElementAttrs)
[ text label ]
buttonStyle : Css.Style
buttonStyle =
Css.batch
[ Css.cursor Css.pointer
, -- Specifying the font can and should go away after bootstrap is removed from application.css
Fonts.baseFont
, Css.textOverflow Css.ellipsis
, Css.overflow Css.hidden
, Css.textDecoration Css.none
, Css.backgroundImage Css.none
, Css.textShadow Css.none
, Css.property "transition" "background-color 0.2s, color 0.2s, box-shadow 0.2s, border 0.2s, border-width 0s"
, Css.boxShadow Css.none
, Css.border Css.zero
, Css.marginBottom Css.zero
, Css.hover [ Css.textDecoration Css.none ]
, Css.display Css.inlineFlex
, Css.alignItems Css.center
, Css.justifyContent Css.center
]
type ColorPalette
= PrimaryColors
| SecondaryColors
| DangerColors
colorStyle : ColorPalette -> Css.Style
colorStyle colorPalette =
let
config =
case colorPalette of
PrimaryColors ->
{ background = Colors.azure
, hover = Colors.azureDark
, text = Colors.white
, shadow = Colors.azureDark
}
SecondaryColors ->
{ background = Colors.white
, hover = Colors.white
, text = Colors.azure
, shadow = Colors.white
}
DangerColors ->
{ background = Colors.red
, hover = Colors.redDark
, text = Colors.white
, shadow = Colors.redDark
}
in
Css.batch
[ Css.color config.text
, Css.backgroundColor config.background
, Css.fontWeight (Css.int 700)
, Css.textAlign Css.center
, Css.borderStyle Css.none
, Css.borderBottomStyle Css.solid
, Css.borderBottomColor config.shadow
, Css.fontStyle Css.normal
, Css.hover
[ Css.color config.text
, Css.backgroundColor config.hover
, Css.disabled [ Css.backgroundColor config.background ]
]
, Css.visited [ Css.color config.text ]
]
sizeStyle : Css.Style
sizeStyle =
let
config =
{ fontSize = 20
, height = 56
, imageHeight = 20
, shadowHeight = 4
, minWidth = 200
}
sizingAttributes =
let
verticalPaddingPx =
2
in
[ Css.minHeight (Css.px config.height)
, Css.paddingTop (Css.px verticalPaddingPx)
, Css.paddingBottom (Css.px verticalPaddingPx)
]
widthAttributes =
[ Css.paddingLeft (Css.px 16)
, Css.paddingRight (Css.px 16)
, Css.minWidth (Css.px 230)
]
lineHeightPx =
22
in
Css.batch
[ Css.fontSize (Css.px config.fontSize)
, Css.borderRadius (Css.px 8)
, Css.lineHeight (Css.px lineHeightPx)
, Css.boxSizing Css.borderBox
, Css.borderWidth (Css.px 1)
, Css.borderBottomWidth (Css.px config.shadowHeight)
, Css.batch sizingAttributes
, Css.batch widthAttributes
]

View File

@ -12,6 +12,7 @@ import Css.Global
import Html as Root
import Html.Styled.Attributes exposing (css)
import ModuleExample exposing (Category(..), ModuleExample)
import Nri.Ui.Button.V9 as Button
import Nri.Ui.Checkbox.V5 as Checkbox
import Nri.Ui.Colors.V1 as Colors
import Nri.Ui.Modal.V6 as Modal
@ -48,26 +49,41 @@ example parentMessage state =
{ name = "Nri.Ui.Modal.V6"
, category = Modals
, content =
[ Modal.launchButton InfoModalMsg [] "Launch Info Modal"
, Modal.launchButton WarningModalMsg [] "Launch Warning Modal"
[ Button.button "Launch Info Modal"
[ Button.onClick (InfoModalMsg (Modal.open "launch-info-modal"))
, Button.custom
[ Html.Styled.Attributes.id "launch-info-modal"
, css [ Css.marginRight (Css.px 16) ]
]
, Button.secondary
, Button.medium
]
, Button.button "Launch Warning Modal"
[ Button.onClick (WarningModalMsg (Modal.open "launch-warning-modal"))
, Button.custom [ Html.Styled.Attributes.id "launch-warning-modal" ]
, Button.secondary
, Button.medium
]
, Modal.info
{ title = { title = "Modal.info", visibleTitle = state.visibleTitle }
{ title = "Modal.info"
, visibleTitle = state.visibleTitle
, wrapMsg = InfoModalMsg
, content =
viewContent state
InfoModalMsg
(Modal.primaryButton ForceClose "Continue")
(Modal.secondaryButton ForceClose "Close")
Button.primary
Button.secondary
}
state.infoModal
, Modal.warning
{ title = { title = "Modal.warning", visibleTitle = state.visibleTitle }
{ title = "Modal.warning"
, visibleTitle = state.visibleTitle
, wrapMsg = WarningModalMsg
, content =
viewContent state
WarningModalMsg
(Modal.dangerButton ForceClose "Continue")
(Modal.secondaryButton ForceClose "Close")
Button.danger
Button.secondary
}
state.warningModal
]
@ -78,11 +94,11 @@ example parentMessage state =
viewContent :
State
-> (Modal.Msg -> Msg)
-> (List (Root.Attribute Msg) -> Html Msg)
-> (List (Root.Attribute Msg) -> Html Msg)
-> Button.Attribute Msg
-> Button.Attribute Msg
-> Modal.FocusableElementAttrs Msg
-> Html Msg
viewContent state wrapMsg primaryButton secondaryButton focusableElementAttrs =
viewContent state wrapMsg firstButtonStyle secondButtonStyle focusableElementAttrs =
div []
[ if state.showX then
Modal.closeButton wrapMsg focusableElementAttrs.firstFocusableElement
@ -92,18 +108,33 @@ viewContent state wrapMsg primaryButton secondaryButton focusableElementAttrs =
, Modal.viewContent [ viewSettings state ]
, if state.showContinue && state.showSecondary then
Modal.viewFooter
[ primaryButton []
, secondaryButton focusableElementAttrs.lastFocusableElement
[ Button.button "Continue"
[ firstButtonStyle
, Button.onClick ForceClose
]
, Button.button "Close"
[ secondButtonStyle
, Button.onClick ForceClose
, Button.custom focusableElementAttrs.lastFocusableElement
]
]
else if state.showContinue then
Modal.viewFooter
[ primaryButton focusableElementAttrs.lastFocusableElement
[ Button.button "Continue"
[ firstButtonStyle
, Button.onClick ForceClose
, Button.custom focusableElementAttrs.lastFocusableElement
]
]
else if state.showSecondary then
Modal.viewFooter
[ secondaryButton focusableElementAttrs.lastFocusableElement
[ Button.button "Close"
[ secondButtonStyle
, Button.onClick ForceClose
, Button.custom focusableElementAttrs.lastFocusableElement
]
]
else