diff --git a/elm.json b/elm.json index a381213e..27429755 100644 --- a/elm.json +++ b/elm.json @@ -45,6 +45,7 @@ "Nri.Ui.SegmentedControl.V6", "Nri.Ui.Select.V5", "Nri.Ui.Svg.V1", + "Nri.Ui.SlideModal.V1", "Nri.Ui.Table.V3", "Nri.Ui.Table.V4", "Nri.Ui.Tabs.V3", diff --git a/src/Nri/Ui/SlideModal/V1.elm b/src/Nri/Ui/SlideModal/V1.elm new file mode 100644 index 00000000..0a197cf1 --- /dev/null +++ b/src/Nri/Ui/SlideModal/V1.elm @@ -0,0 +1,308 @@ +module Nri.Ui.SlideModal.V1 exposing + ( Config, Panel + , State, closed, open + , view + ) + +{-| + +@docs Config, Panel +@docs State, closed, open +@docs view + +-} + +import Accessibility.Styled as Html exposing (..) +import Accessibility.Styled.Aria exposing (labelledBy) +import Accessibility.Styled.Role as Role +import Accessibility.Styled.Style +import Accessibility.Styled.Widget as Widget +import Css +import Css.Global +import Html.Styled +import Html.Styled.Attributes exposing (css) +import Html.Styled.Events exposing (onClick) +import Nri.Ui +import Nri.Ui.AssetPath exposing (Asset(..)) +import Nri.Ui.Button.V8 as Button +import Nri.Ui.Colors.Extra +import Nri.Ui.Colors.V1 as Colors +import Nri.Ui.Fonts.V1 as Fonts +import Nri.Ui.Icon.V3 as Icon +import Nri.Ui.Text.V2 as Text + + +{-| -} +type alias Config msg = + { panels : List (Panel msg) + , height : Css.Vh + , parentMsg : State -> msg + } + + +{-| -} +type State + = State (Maybe Int) + + +{-| Create the open state for the modal (the first panel will show). +-} +open : State +open = + State (Just 0) + + +{-| Close the modal. +-} +closed : State +closed = + State Nothing + + +{-| View the modal (includes the modal backdrop). +-} +view : Config msg -> State -> Html msg +view config state = + summarize state config.panels + |> Maybe.map (viewPanels config.parentMsg) + |> Maybe.map (viewModal config.height >> viewBackdrop) + |> Maybe.withDefault (Html.text "") + + +type alias Summary msg = + { current : Panel msg + , upcoming : List ( State, String ) + , previous : List ( State, String ) + } + + +summarize : State -> List (Panel msg) -> Maybe (Summary msg) +summarize (State state) panels = + let + indexedPanels = + List.indexedMap + (\i { title } -> ( State (Just i), title )) + panels + + toSummary current currentPanel = + { current = currentPanel + , upcoming = List.drop (current + 1) indexedPanels + , previous = List.take current indexedPanels + } + in + Maybe.andThen + (\current -> + List.head (List.drop current panels) + |> Maybe.map (toSummary current) + ) + state + + +viewModal : Css.Vh -> ( String, List (Html msg) ) -> Html msg +viewModal height ( labelledById, panels ) = + Nri.Ui.styled div + "modal-container" + [ Css.width (Css.px 600) + , Css.height height + , Css.maxHeight <| Css.calc (Css.vh 100) Css.minus (Css.px 100) + , Css.padding4 (Css.px 35) Css.zero (Css.px 25) Css.zero + , Css.margin2 (Css.px 75) Css.auto + , Css.backgroundColor Colors.white + , Css.borderRadius (Css.px 20) + , Css.property "box-shadow" "0 1px 10px 0 rgba(0, 0, 0, 0.35)" + , Css.displayFlex + , Css.alignItems Css.center + , Css.flexDirection Css.column + , Css.flexWrap Css.noWrap + , Fonts.baseFont + ] + [ Role.dialog + , Widget.modal True + , labelledBy labelledById + ] + panels + + +viewBackdrop : Html msg -> Html msg +viewBackdrop modal = + Nri.Ui.styled div + "modal-backdrop-container" + (Css.backgroundColor (Nri.Ui.Colors.Extra.withAlpha 0.9 Colors.navy) + :: [ Css.height (Css.vh 100) + , Css.left Css.zero + , Css.overflow Css.hidden + , Css.position Css.fixed + , Css.top Css.zero + , Css.width (Css.pct 100) + , Css.zIndex (Css.int 200) + , Css.displayFlex + , Css.alignItems Css.center + , Css.justifyContent Css.center + ] + ) + [] + [ -- This global