noredink-ui/styleguide-app/Examples/Modal.elm

343 lines
13 KiB
Elm
Raw Normal View History

2020-03-31 22:43:32 +03:00
module Examples.Modal exposing (Msg, State, example)
2018-08-29 22:09:22 +03:00
{-|
2020-03-31 22:43:32 +03:00
@docs Msg, State, example
2018-08-29 22:09:22 +03:00
-}
2019-08-17 01:47:21 +03:00
import Accessibility.Styled as Html exposing (Html, div, h3, h4, p, span, text)
2020-06-19 23:41:28 +03:00
import AtomicDesignType exposing (AtomicDesignType(..))
import Category exposing (Category(..))
2018-08-29 22:09:22 +03:00
import Css exposing (..)
2020-09-02 23:44:39 +03:00
import Debug.Control as Control exposing (Control)
2020-03-31 23:20:03 +03:00
import Example exposing (Example)
import Html as Root
import Html.Styled.Attributes as Attributes
import KeyboardSupport exposing (Direction(..), Key(..))
2020-01-29 04:10:20 +03:00
import Nri.Ui.Button.V10 as Button
2019-06-11 00:28:38 +03:00
import Nri.Ui.Checkbox.V5 as Checkbox
import Nri.Ui.ClickableText.V3 as ClickableText
2018-08-29 22:09:22 +03:00
import Nri.Ui.Colors.V1 as Colors
2020-09-02 20:12:59 +03:00
import Nri.Ui.Modal.V11 as Modal
2019-08-17 01:47:21 +03:00
import Nri.Ui.Text.V4 as Text
2018-08-29 22:09:22 +03:00
{-| -}
type alias State =
2020-07-03 01:09:07 +03:00
{ state : Modal.Model
2020-09-02 23:44:39 +03:00
, settings : Control Settings
2020-07-03 01:09:07 +03:00
}
{-| -}
init : State
init =
{ state = Modal.init
, settings = initModalSettings
}
type alias Settings =
{ title : String
2019-06-11 00:53:38 +03:00
, showX : Bool
2019-06-11 03:12:35 +03:00
, showContinue : Bool
2019-06-11 04:32:54 +03:00
, showSecondary : Bool
2019-06-11 21:26:24 +03:00
, dismissOnEscAndOverlayClick : Bool
2020-09-02 23:59:02 +03:00
, content : String
, attributes : List Modal.Attribute
2019-06-11 00:28:38 +03:00
}
2020-09-02 23:44:39 +03:00
initModalSettings : Control Settings
2020-07-03 01:09:07 +03:00
initModalSettings =
2020-09-02 23:44:39 +03:00
Control.record Settings
|> Control.field "Modal title" (Control.string "Modal Title")
|> Control.field "X button" (Control.bool True)
|> Control.field "Continue button" (Control.bool True)
|> Control.field "Close button" (Control.bool True)
2020-09-02 23:44:39 +03:00
|> Control.field "dismissOnEscAndOverlayClick" (Control.bool True)
|> Control.field "Content"
2020-09-02 23:59:02 +03:00
(Control.stringTextarea <|
String.join "\n\n"
[ "Generally, you'll want to pair the Modal.warning theme with the Button.danger theme and the Modal.info theme with the Button.primary theme."
, "Muffin liquorice powder liquorice jujubes biscuit cookie candy canes lemon drops. Liquorice powder carrot cake dragée icing tootsie roll apple pie lemon drops lemon drops. Jujubes danish bear claw cotton candy. Dragée apple pie tiramisu. Sugar plum dessert pastry marzipan chocolate cake dragée sesame snaps. Marshmallow gingerbread lemon drops. Brownie chocolate fruitcake pastry. Powder jelly beans jujubes. Croissant macaroon dessert cookie candy canes jelly jujubes. Muffin liquorice ice cream wafer donut danish soufflé dragée chocolate bar. Candy croissant candy wafer toffee lemon drops croissant danish sugar plum. Cookie cake candy canes. Pastry powder muffin soufflé tootsie roll sweet cookie tiramisu."
, "Candy cake danish gingerbread. Caramels toffee cupcake toffee sweet. Gummi bears candy cheesecake sweet. Pie gingerbread sugar plum halvah muffin icing marzipan wafer icing. Candy fruitcake gummies icing marzipan. Halvah jelly beans candy candy canes biscuit bonbon sesame snaps. Biscuit carrot cake croissant cake chocolate lollipop candy biscuit croissant. Topping jujubes apple pie croissant chocolate cake. Liquorice cookie dragée gummies cotton candy fruitcake lemon drops candy canes. Apple pie lemon drops gummies cake chocolate bar cake jelly-o tiramisu. Chocolate bar icing pudding marshmallow cake soufflé soufflé muffin. Powder lemon drops biscuit sugar plum cupcake carrot cake powder cake dragée. Bear claw gummi bears liquorice sweet roll."
]
)
|> Control.field "Modal Attributes" controlAttributes
controlAttributes : Control (List Modal.Attribute)
controlAttributes =
Control.record (\a b c -> a :: b :: c :: [])
|> Control.field "Theme" controlTheme
|> Control.field "Title visibility" controlTitleVisibility
|> Control.field "Custom css" controlCss
2020-09-02 23:53:40 +03:00
2020-09-03 00:04:06 +03:00
controlTitleVisibility : Control Modal.Attribute
controlTitleVisibility =
Control.choice
[ ( "showTitle", Control.value Modal.showTitle )
, ( "hideTitle", Control.value Modal.hideTitle )
]
2020-09-02 23:53:40 +03:00
controlTheme : Control Modal.Attribute
controlTheme =
Control.choice
[ ( "info", Control.value Modal.info )
, ( "warning", Control.value Modal.warning )
]
2018-08-29 22:09:22 +03:00
controlCss : Control Modal.Attribute
controlCss =
Control.map Modal.css <|
Control.choice
[ ( "[]", Control.value [] )
, ( "[ Css.borderRadius Css.zero ]", Control.value [ Css.borderRadius Css.zero ] )
, ( "[ Css.width (Css.px 900) ]", Control.value [ Css.width (Css.px 900) ] )
]
2018-08-29 22:09:22 +03:00
{-| -}
2020-03-31 23:20:03 +03:00
example : Example State Msg
2020-03-31 22:43:32 +03:00
example =
2020-09-02 20:12:59 +03:00
{ name = "Nri.Ui.Modal.V11"
2020-03-31 22:43:32 +03:00
, categories = [ Modals ]
2020-06-20 00:16:10 +03:00
, atomicDesignType = Organism
2020-09-03 00:19:41 +03:00
, keyboardSupport =
[ { keys = [ KeyboardSupport.Tab ]
, result = "Moves focus to the next button within the modal or wraps back to the first element within the modal."
}
, { keys = [ KeyboardSupport.Tab, KeyboardSupport.Shift ]
, result = "Moves focus to the previous button within the modal or wraps back to the last element within the modal."
}
, { keys = [ KeyboardSupport.Esc ]
, result = "If 'dismissOnEscAndOverlayClick' is set to true, closes the modal. Else, does nothing."
}
]
2020-03-31 22:43:32 +03:00
, state = init
, update = update
2020-03-31 22:48:26 +03:00
, subscriptions = subscriptions
2020-03-31 22:43:32 +03:00
, view =
\state ->
let
2020-09-02 23:44:39 +03:00
settings =
Control.currentValue state.settings
in
2020-09-02 23:44:39 +03:00
[ Control.view UpdateSettings state.settings
|> Html.fromUnstyled
2020-09-02 23:53:40 +03:00
, Button.button "Launch Modal"
[ Button.onClick (OpenModal "launch-modal")
, Button.custom [ Attributes.id "launch-modal" ]
2020-03-31 22:43:32 +03:00
, Button.secondary
, Button.medium
]
2020-09-02 20:48:52 +03:00
, Modal.view
2020-09-03 00:04:06 +03:00
{ title = settings.title
2020-09-02 20:48:52 +03:00
, wrapMsg = ModalMsg
2020-09-02 23:53:40 +03:00
, focusManager = makeFocusManager settings
2020-09-02 20:48:52 +03:00
}
settings.attributes
2020-09-02 20:48:52 +03:00
state.state
]
2018-08-29 22:09:22 +03:00
}
2020-09-02 23:53:40 +03:00
makeFocusManager : Settings -> Modal.FocusManager Msg
makeFocusManager settings =
2020-07-03 01:09:07 +03:00
case ( settings.showX, settings.showContinue, settings.showSecondary ) of
( True, True, True ) ->
2020-07-03 01:09:07 +03:00
Modal.MultipleFocusableElements <|
\modalOptions ->
{ content =
[ modalOptions.closeButton modalOptions.firstFocusableElement
2020-09-02 23:59:02 +03:00
, viewModalContent settings.content
2019-10-23 18:02:52 +03:00
]
2020-07-03 01:09:07 +03:00
, footer =
[ Button.button "Continue"
2020-09-02 23:53:40 +03:00
[ Button.premium
2020-07-03 01:09:07 +03:00
, Button.onClick ForceClose
, Button.large
, Button.custom [ modalOptions.autofocusElement ]
]
, ClickableText.button "Close"
[ ClickableText.onClick ForceClose
, ClickableText.large
, ClickableText.custom modalOptions.lastFocusableElement
, ClickableText.css [ Css.marginTop (Css.px 12) ]
]
]
}
( True, False, True ) ->
2020-07-03 01:09:07 +03:00
Modal.MultipleFocusableElements <|
\modalOptions ->
{ content =
[ modalOptions.closeButton modalOptions.firstFocusableElement
2020-09-02 23:59:02 +03:00
, viewModalContent settings.content
2019-10-23 18:02:52 +03:00
]
2020-07-03 01:09:07 +03:00
, footer =
[ ClickableText.button "Close"
[ ClickableText.onClick ForceClose
, ClickableText.large
, ClickableText.custom (modalOptions.autofocusElement :: modalOptions.lastFocusableElement)
, ClickableText.css [ Css.marginTop (Css.px 12) ]
]
]
}
( True, False, False ) ->
2020-07-03 01:09:07 +03:00
Modal.OneFocusableElement
(\{ onlyFocusableElement, closeButton } ->
{ content =
2019-10-23 19:10:05 +03:00
[ closeButton onlyFocusableElement
2020-09-02 23:59:02 +03:00
, viewModalContent settings.content
2019-10-23 18:02:52 +03:00
]
2020-07-03 01:09:07 +03:00
, footer = []
}
2019-10-23 18:02:52 +03:00
)
( True, True, False ) ->
2020-07-03 01:09:07 +03:00
Modal.MultipleFocusableElements <|
\modalOptions ->
{ content =
[ modalOptions.closeButton modalOptions.firstFocusableElement
2020-09-02 23:59:02 +03:00
, viewModalContent settings.content
2019-10-23 18:02:52 +03:00
]
2020-07-03 01:09:07 +03:00
, footer =
[ Button.button "Continue"
2020-09-02 23:53:40 +03:00
[ Button.premium
2020-07-03 01:09:07 +03:00
, Button.onClick ForceClose
, Button.custom (modalOptions.autofocusElement :: modalOptions.lastFocusableElement)
, Button.large
]
]
}
( False, True, True ) ->
2020-07-03 01:09:07 +03:00
Modal.MultipleFocusableElements <|
\modalOptions ->
2020-09-02 23:59:02 +03:00
{ content = [ viewModalContent settings.content ]
2020-07-03 01:09:07 +03:00
, footer =
[ Button.button "Continue"
2020-09-02 23:53:40 +03:00
[ Button.premium
2020-07-03 01:09:07 +03:00
, Button.onClick ForceClose
, Button.custom (modalOptions.autofocusElement :: modalOptions.firstFocusableElement)
, Button.large
]
, ClickableText.button "Close"
[ ClickableText.onClick ForceClose
, ClickableText.large
, ClickableText.custom modalOptions.lastFocusableElement
, ClickableText.css [ Css.marginTop (Css.px 12) ]
]
2019-10-23 18:02:52 +03:00
]
2020-07-03 01:09:07 +03:00
}
2019-06-11 03:45:21 +03:00
( False, False, True ) ->
2020-07-03 01:09:07 +03:00
Modal.OneFocusableElement
(\{ onlyFocusableElement } ->
2020-09-02 23:59:02 +03:00
{ content = [ viewModalContent settings.content ]
2020-07-03 01:09:07 +03:00
, footer =
[ ClickableText.button "Close"
[ ClickableText.onClick ForceClose
, ClickableText.large
, ClickableText.custom onlyFocusableElement
, ClickableText.css [ Css.marginTop (Css.px 12) ]
]
2019-10-23 18:02:52 +03:00
]
2020-07-03 01:09:07 +03:00
}
2019-10-23 18:02:52 +03:00
)
( False, True, False ) ->
2020-07-03 01:09:07 +03:00
Modal.OneFocusableElement
(\{ onlyFocusableElement } ->
2020-09-02 23:59:02 +03:00
{ content = [ viewModalContent settings.content ]
2020-07-03 01:09:07 +03:00
, footer =
[ Button.button "Continue"
2020-09-02 23:53:40 +03:00
[ Button.premium
2020-07-03 01:09:07 +03:00
, Button.onClick ForceClose
, Button.custom onlyFocusableElement
, Button.large
]
2019-10-23 18:02:52 +03:00
]
2020-07-03 01:09:07 +03:00
}
2019-10-23 18:02:52 +03:00
)
( False, False, False ) ->
2020-07-03 01:09:07 +03:00
Modal.OneFocusableElement
2019-10-23 19:10:05 +03:00
(\_ ->
2020-09-02 23:59:02 +03:00
{ content = [ viewModalContent settings.content ]
2020-07-03 01:09:07 +03:00
, footer = []
}
2019-10-23 18:02:52 +03:00
)
2019-06-11 03:52:19 +03:00
2020-09-02 23:59:02 +03:00
viewModalContent : String -> Html msg
viewModalContent content =
2019-08-17 01:47:21 +03:00
Text.mediumBody
2020-09-02 23:59:02 +03:00
[ span
[ Attributes.css [ whiteSpace preLine ] ]
[ text content ]
2019-08-17 01:47:21 +03:00
]
2018-08-29 22:09:22 +03:00
{-| -}
2019-06-11 00:28:38 +03:00
type Msg
2020-09-02 23:53:40 +03:00
= OpenModal String
2020-07-03 01:33:51 +03:00
| ModalMsg Modal.Msg
2019-06-11 03:12:35 +03:00
| ForceClose
2020-09-02 23:44:39 +03:00
| UpdateSettings (Control Settings)
2018-08-29 22:09:22 +03:00
{-| -}
update : Msg -> State -> ( State, Cmd Msg )
update msg state =
2019-06-12 21:12:37 +03:00
let
2020-07-03 01:09:07 +03:00
settings =
state.settings
2019-06-12 21:12:37 +03:00
updateConfig =
2020-09-02 23:44:39 +03:00
{ dismissOnEscAndOverlayClick =
(Control.currentValue settings).dismissOnEscAndOverlayClick
}
2019-06-12 21:12:37 +03:00
in
2018-08-29 22:09:22 +03:00
case msg of
2020-09-02 23:53:40 +03:00
OpenModal returnFocusTo ->
2020-09-02 20:34:12 +03:00
let
( newState, cmd ) =
Modal.open returnFocusTo
in
2020-09-02 23:53:40 +03:00
( { state | state = newState }
2020-09-02 20:34:12 +03:00
, Cmd.map ModalMsg cmd
)
2020-07-03 01:33:51 +03:00
2020-07-03 01:09:07 +03:00
ModalMsg modalMsg ->
case Modal.update updateConfig modalMsg state.state of
2020-09-02 20:34:12 +03:00
( newState, cmd ) ->
2020-07-03 01:09:07 +03:00
( { state | state = newState }
2020-09-02 20:34:12 +03:00
, Cmd.map ModalMsg cmd
)
2018-08-29 22:09:22 +03:00
2019-06-11 03:12:35 +03:00
ForceClose ->
2020-09-02 20:34:12 +03:00
let
( newState, cmd ) =
Modal.close state.state
in
( { state | state = newState }
, Cmd.map ModalMsg cmd
2019-06-11 03:12:35 +03:00
)
2020-09-02 23:44:39 +03:00
UpdateSettings value ->
( { state | settings = value }, Cmd.none )
2018-08-29 22:09:22 +03:00
{-| -}
subscriptions : State -> Sub Msg
subscriptions model =
2020-07-03 01:09:07 +03:00
Sub.map ModalMsg (Modal.subscriptions model.state)