adds basic carousel and an usage example

This commit is contained in:
Celso Bonutti 2022-06-15 19:34:30 -03:00
parent d4c99250c7
commit 6df640cf65
3 changed files with 295 additions and 0 deletions

View File

@ -0,0 +1,94 @@
module Nri.Ui.Carousel.V1 exposing (..)
import Css exposing (..)
import Html.Styled as Html exposing (Html)
import Nri.Ui
import Nri.Ui.Tooltip.V3 as Tooltip
import TabsInternal.V2 as TabsInternal
type Tab id msg
= Tab (TabsInternal.Tab id msg)
type Attribute id msg
= Attribute (TabsInternal.Tab id msg -> TabsInternal.Tab id msg)
type TabPosition
= Before
| After
{-| Tooltip defaults: `[Tooltip.smallPadding, Tooltip.onBottom, Tooltip.fitToContent]`
-}
withTooltip : List (Tooltip.Attribute msg) -> Attribute id msg
withTooltip attributes =
Attribute (\tab -> { tab | tabTooltip = attributes })
{-| Makes it so that the tab can't be clicked or focused via keyboard navigation
-}
disabled : Bool -> Attribute id msg
disabled isDisabled =
Attribute (\tab -> { tab | disabled = isDisabled })
{-| -}
slideHtml : Html msg -> Attribute id msg
slideHtml content =
Attribute (\tab -> { tab | panelView = content })
labelledBy : String -> Attribute id msg
labelledBy labelledById =
Attribute (\tab -> { tab | labelledBy = Just labelledById })
tabHtml : Html Never -> Attribute id msg
tabHtml content =
Attribute (\tab -> { tab | tabView = [ Html.map never content ] })
{-| -}
buildTab : { id : id, idString : String } -> List (Attribute id msg) -> Tab id msg
buildTab config attributes =
Tab (TabsInternal.fromList config (List.map (\(Attribute f) -> f) attributes))
view :
{ focusAndSelect : { select : id, focus : Maybe String } -> msg
, selected : id
, tabs : List (Tab id msg)
, tabStyles : Int -> Bool -> List Style
, tabListStyles : List Style
, containerStyles : List Style
, tabListPosition : TabPosition
}
-> Html msg
view config =
let
{ tabList, tabPanels } =
TabsInternal.views
{ focusAndSelect = config.focusAndSelect
, selected = config.selected
, tabs = List.map (\(Tab t) -> t) config.tabs
, tabStyles = config.tabStyles
, tabListStyles = config.tabListStyles
}
in
Nri.Ui.styled Html.div
"Nri-Ui-Carousel__container"
config.containerStyles
[]
(case config.tabListPosition of
Before ->
[ tabList
, tabPanels
]
After ->
[ tabPanels
, tabList
]
)

View File

@ -6,6 +6,7 @@ import Examples.AssignmentIcon as AssignmentIcon
import Examples.Balloon as Balloon
import Examples.BreadCrumbs as BreadCrumbs
import Examples.Button as Button
import Examples.Carousel as Carousel
import Examples.Checkbox as Checkbox
import Examples.ClickableSvg as ClickableSvg
import Examples.ClickableText as ClickableText
@ -136,6 +137,25 @@ all =
ButtonState childState ->
Just childState
_ ->
Nothing
)
, Carousel.example
|> Example.wrapMsg CarouselMsg
(\msg ->
case msg of
CarouselMsg childMsg ->
Just childMsg
_ ->
Nothing
)
|> Example.wrapState CarouselState
(\msg ->
case msg of
CarouselState childState ->
Just childState
_ ->
Nothing
)
@ -794,6 +814,7 @@ type State
| BalloonState Balloon.State
| BreadCrumbsState BreadCrumbs.State
| ButtonState Button.State
| CarouselState Carousel.State
| CheckboxState Checkbox.State
| ClickableSvgState ClickableSvg.State
| ClickableTextState ClickableText.State
@ -836,6 +857,7 @@ type Msg
| BalloonMsg Balloon.Msg
| BreadCrumbsMsg BreadCrumbs.Msg
| ButtonMsg Button.Msg
| CarouselMsg Carousel.Msg
| CheckboxMsg Checkbox.Msg
| ClickableSvgMsg ClickableSvg.Msg
| ClickableTextMsg ClickableText.Msg

View File

@ -0,0 +1,179 @@
module Examples.Carousel exposing
( example
, State
, Msg
)
{-|
@docs example
@docs State, msg
-}
import Browser.Dom as Dom
import Category exposing (Category(..))
import Css
import Debug.Control as Control exposing (Control)
import Example exposing (Example)
import Html.Styled as Html exposing (fromUnstyled)
import Html.Styled.Attributes as Attributes
import KeyboardSupport exposing (Key(..))
import Nri.Ui.Carousel.V1 as Carousel exposing (Tab, TabPosition(..))
import Nri.Ui.Colors.V1 as Colors
import Task
type Id
= First
| Second
| Third
| Fourth
type alias State =
{ selected : Id
, settings : Control Settings
}
init : State
init =
{ selected = First
, settings = initSettings
}
type alias Settings =
{ tabListPosition : Carousel.TabPosition }
initSettings : Control Settings
initSettings =
Control.record Settings
|> Control.field "tabListPosition"
(Control.choice
[ ( "Before", Control.value Before )
, ( "After", Control.value After )
]
)
type Msg
= FocusAndSelectTab { select : Id, focus : Maybe String }
| Focused (Result Dom.Error ())
| SetSettings (Control Settings)
update : Msg -> State -> ( State, Cmd Msg )
update msg model =
case msg of
FocusAndSelectTab { select, focus } ->
( { model | selected = select }
, focus
|> Maybe.map (Dom.focus >> Task.attempt Focused)
|> Maybe.withDefault Cmd.none
)
Focused error ->
( model, Cmd.none )
SetSettings settings ->
( { model | settings = settings }, Cmd.none )
exampleName : String
exampleName =
"Carousel"
example : Example State Msg
example =
{ name = exampleName
, version = 1
, categories = [ Layout ]
, keyboardSupport =
[ { keys = [ KeyboardSupport.Tab ]
, result = "Move focus to the currently-selected Tab's tab panel"
}
, { keys = [ Arrow KeyboardSupport.Left ]
, result = "Select the tab to the left of the currently-selected Tab"
}
, { keys = [ Arrow KeyboardSupport.Right ]
, result = "Select the tab to the right of the currently-selected Tab"
}
]
, state = init
, update = update
, subscriptions = \_ -> Sub.none
, preview =
[]
, view =
\ellieLinkConfig model ->
let
settings =
Control.currentValue model.settings
in
[ Control.view SetSettings model.settings |> fromUnstyled
, Carousel.view
{ focusAndSelect = FocusAndSelectTab
, selected = model.selected
, tabListStyles = tabListStyles
, tabStyles = tabStyles
, containerStyles = containerStyles
, tabListPosition = settings.tabListPosition
, tabs = allTabs
}
]
}
containerStyles =
[ Css.margin (Css.px 20) ]
tabListStyles =
[ Css.displayFlex
, Css.property "gap" "20px"
]
tabStyles : Int -> Bool -> List Css.Style
tabStyles _ isSelected =
let
( backgroundColor, textColor ) =
if isSelected then
( Colors.azure, Colors.white )
else
( Colors.gray92, Colors.gray45 )
in
[ Css.padding2 (Css.px 10) (Css.px 20)
, Css.backgroundColor backgroundColor
, Css.borderRadius (Css.px 8)
, Css.border Css.zero
, Css.color textColor
]
slideStyles =
[ Css.marginTop (Css.px 20)
, Css.padding2 (Css.px 10) (Css.px 30)
, Css.borderRadius (Css.px 4)
]
allTabs : List (Tab Id Msg)
allTabs =
[ ( First, "first", "1" )
, ( Second, "second", "2" )
, ( Third, "third", "3" )
, ( Fourth, "fourth", "4" )
]
|> List.map
(\( id, idString, buttonText ) ->
Carousel.buildTab { id = id, idString = idString ++ "-slide" }
[ Carousel.tabHtml (Html.text buttonText)
, Carousel.slideHtml (Html.div [ Attributes.css slideStyles ] [ Html.text <| idString ++ " slide" ])
]
)