mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-11-24 00:42:29 +03:00
adds basic carousel and an usage example
This commit is contained in:
parent
d4c99250c7
commit
6df640cf65
94
src/Nri/Ui/Carousel/V1.elm
Normal file
94
src/Nri/Ui/Carousel/V1.elm
Normal 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
|
||||
]
|
||||
)
|
@ -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
|
||||
|
179
styleguide-app/Examples/Carousel.elm
Normal file
179
styleguide-app/Examples/Carousel.elm
Normal 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" ])
|
||||
]
|
||||
)
|
Loading…
Reference in New Issue
Block a user