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

475 lines
16 KiB
Elm
Raw Normal View History

2018-09-26 17:02:10 +03:00
module Examples.SegmentedControl exposing
2020-03-31 22:43:32 +03:00
( Msg, State
2018-09-26 17:02:10 +03:00
, example
)
2018-03-24 05:05:34 +03:00
{-|
2020-03-31 22:43:32 +03:00
@docs Msg, State
@docs example
2018-03-24 05:05:34 +03:00
-}
2020-08-05 03:52:30 +03:00
import Accessibility.Styled as Html exposing (Html)
2022-03-25 00:53:12 +03:00
import Accessibility.Styled.Role as Role
import Accessibility.Styled.Widget as Widget
2020-08-06 01:19:09 +03:00
import Browser.Dom as Dom
import Category exposing (Category(..))
2020-08-05 04:08:16 +03:00
import Css
import Debug.Control as Control exposing (Control)
2022-03-25 00:56:36 +03:00
import Debug.Control.View as ControlView
2020-03-31 23:20:03 +03:00
import Example exposing (Example)
2022-03-15 21:06:13 +03:00
import Html.Styled.Attributes exposing (css)
import KeyboardSupport exposing (Key(..))
2022-03-25 00:53:12 +03:00
import Nri.Ui.Colors.Extra exposing (withAlpha)
import Nri.Ui.Colors.V1 as Colors
2022-03-25 00:53:12 +03:00
import Nri.Ui.Fonts.V1 as Fonts
2021-04-06 22:50:09 +03:00
import Nri.Ui.SegmentedControl.V14 as SegmentedControl
2019-10-24 23:23:52 +03:00
import Nri.Ui.Svg.V1 as Svg exposing (Svg)
2020-09-09 00:06:47 +03:00
import Nri.Ui.Tooltip.V2 as Tooltip
2019-10-24 21:08:28 +03:00
import Nri.Ui.UiIcon.V1 as UiIcon
import String exposing (toLower)
2020-08-06 01:19:09 +03:00
import Task
2018-03-24 05:05:34 +03:00
2022-03-29 00:16:34 +03:00
moduleName : String
moduleName =
"SegmentedControl"
version : Int
version =
14
2018-03-24 05:05:34 +03:00
{-| -}
2020-03-31 23:20:03 +03:00
example : Example State Msg
2020-03-31 22:43:32 +03:00
example =
2022-03-29 00:16:34 +03:00
{ name = moduleName
, version = version
2020-03-31 22:43:32 +03:00
, state = init
, update = update
2020-03-31 22:48:26 +03:00
, subscriptions = \_ -> Sub.none
2022-03-25 00:53:12 +03:00
, preview = [ viewPreview ]
2020-03-31 22:43:32 +03:00
, view =
\ellieLinkConfig state ->
2020-03-31 22:43:32 +03:00
let
options =
Control.currentValue state.optionsControl
2022-03-25 01:54:46 +03:00
pageOptions =
List.take options.count (buildOptions options state.pageTooltip)
2022-03-25 02:11:53 +03:00
radioOptions =
List.take options.count (buildRadioOptions options state.radioTooltip options.content)
2020-03-31 22:43:32 +03:00
in
2022-03-25 00:56:36 +03:00
[ ControlView.view
2022-03-30 01:52:01 +03:00
{ ellieLinkConfig = ellieLinkConfig
, name = moduleName
2022-03-29 00:16:34 +03:00
, version = version
, update = ChangeOptions
2022-03-25 00:56:36 +03:00
, settings = state.optionsControl
, mainType = "RootHtml.Html msg"
2022-04-13 03:32:46 +03:00
, extraImports = []
2022-03-25 00:56:36 +03:00
, toExampleCode =
\settings ->
2022-03-25 01:54:46 +03:00
[ { sectionName = "view"
, code =
2022-03-29 00:16:34 +03:00
[ moduleName ++ ".view "
2022-03-25 01:54:46 +03:00
, " { focusAndSelect = FocusAndSelectPage"
, " , options = " ++ ControlView.codeFromList pageOptions
, " , selected = \"" ++ Debug.toString state.page ++ "\""
, " , positioning = " ++ Tuple.first options.positioning
, " , toUrl = Nothing"
, " }"
]
|> String.join "\n"
}
2022-03-25 02:11:53 +03:00
, { sectionName = "viewRadioGroup"
, code =
2022-03-29 00:16:34 +03:00
[ moduleName ++ ".viewRadioGroup"
2022-03-25 02:18:21 +03:00
, " { onSelect = SelectRadio"
, " , options = " ++ ControlView.codeFromList radioOptions
, " , selected = " ++ Debug.toString state.optionallySelected
, " , positioning = " ++ Tuple.first options.positioning
, " , legend = \"SegmentedControls 'viewSelectRadio' example\""
2022-03-25 02:11:53 +03:00
, " }"
]
|> String.join "\n"
}
2022-03-25 00:56:36 +03:00
]
}
2020-08-05 04:08:16 +03:00
, Html.h3 [ css [ Css.marginBottom Css.zero ] ]
[ Html.code [] [ Html.text "view" ] ]
, Html.p [ css [ Css.marginTop (Css.px 1) ] ]
2020-08-06 00:03:48 +03:00
[ Html.text "Use in cases where it would also be reasonable to use Tabs." ]
2020-08-05 03:52:30 +03:00
, SegmentedControl.view
2020-09-09 00:35:36 +03:00
{ focusAndSelect = FocusAndSelectPage
2020-08-05 05:30:24 +03:00
, selected = state.page
2022-03-25 01:54:46 +03:00
, positioning = Tuple.second options.positioning
2020-08-05 05:06:28 +03:00
, toUrl = Nothing
2022-03-25 01:54:46 +03:00
, options = List.map Tuple.second pageOptions
2020-03-31 22:43:32 +03:00
}
2020-08-05 04:08:16 +03:00
, Html.h3 [ css [ Css.marginBottom Css.zero ] ]
2020-08-05 23:20:48 +03:00
[ Html.code [] [ Html.text "viewRadioGroup" ] ]
2020-08-05 04:08:16 +03:00
, Html.p [ css [ Css.marginTop (Css.px 1) ] ]
2020-08-06 00:03:48 +03:00
[ Html.text "Use in cases where it would be reasonable to use radio buttons for the same purpose." ]
2020-08-05 23:20:48 +03:00
, SegmentedControl.viewRadioGroup
2020-08-06 02:22:33 +03:00
{ legend = "SegmentedControls 'viewSelectRadio' example"
2020-08-06 01:25:26 +03:00
, onSelect = SelectRadio
2022-03-25 02:11:53 +03:00
, options = List.map Tuple.second radioOptions
, selected = state.optionallySelected
2022-03-25 01:54:46 +03:00
, positioning = Tuple.second options.positioning
}
2020-03-31 22:43:32 +03:00
]
2021-11-12 01:54:56 +03:00
, categories = [ Layout, Inputs ]
, keyboardSupport =
2020-08-06 01:58:40 +03:00
[ { keys = [ KeyboardSupport.Tab ]
, result = "Move focus to the currently-selected Control's content"
}
, { keys = [ Arrow KeyboardSupport.Left ]
, result = "Select the Control to the left of the current selection"
}
, { keys = [ Arrow KeyboardSupport.Right ]
, result = "Select the Control to the right of the current selection"
}
]
2018-03-24 05:05:34 +03:00
}
2022-03-25 00:53:12 +03:00
viewPreview : Html msg
viewPreview =
Html.div
[ Role.img
, Widget.hidden True
, css
[ Css.displayFlex
, Css.justifyContent Css.stretch
, Css.color Colors.navy
, Fonts.baseFont
, Css.fontSize (Css.px 15)
, Css.fontWeight Css.bold
]
]
[ Html.div
[ css
[ Css.padding2 (Css.px 6) (Css.px 15)
, Css.border3 (Css.px 1) Css.solid Colors.azure
, Css.borderTopLeftRadius (Css.px 8)
, Css.borderBottomLeftRadius (Css.px 8)
, Css.backgroundColor Colors.glacier
, Css.boxShadow5 Css.inset Css.zero (Css.px 3) Css.zero (withAlpha 0.2 Colors.gray20)
]
]
[ Html.text "Abc" ]
, Html.div
[ css
[ Css.padding2 (Css.px 6) (Css.px 15)
, Css.border3 (Css.px 1) Css.solid Colors.azure
, Css.borderTopRightRadius (Css.px 8)
, Css.borderBottomRightRadius (Css.px 8)
, Css.backgroundColor Colors.white
, Css.boxShadow5 Css.inset Css.zero (Css.px -2) Css.zero Colors.azure
]
]
[ Html.text "Def" ]
]
2020-08-05 05:30:24 +03:00
type Page
= Flag
| Sprout
| Star
| Sapling
| Attention
| Tree
| Premium
| Activity
2022-03-25 01:54:46 +03:00
buildOptions : { options | content : Content, longContent : Bool, tooltips : Bool } -> Maybe Page -> List ( String, SegmentedControl.Option Page Msg )
2020-09-09 00:47:38 +03:00
buildOptions { content, longContent, tooltips } openTooltip =
2020-08-05 05:30:24 +03:00
let
2020-08-05 07:35:10 +03:00
buildOption value icon_ =
2020-09-09 00:47:38 +03:00
let
2022-03-25 01:54:46 +03:00
( maybeIcon, label ) =
getIconAndLabel content icon_ (Debug.toString value)
valueStr =
"\"" ++ Debug.toString value ++ "\""
2020-09-09 00:47:38 +03:00
in
2022-03-25 01:54:46 +03:00
( [ "{ icon = " ++ Debug.toString (Maybe.map Tuple.first maybeIcon)
, ", label = text " ++ valueStr
, ", value = " ++ valueStr
2022-03-29 00:16:34 +03:00
, ", idString = String.toLower " ++ valueStr
2022-03-25 01:54:46 +03:00
, ", attributes = []"
, ", tabTooltip = "
++ (if tooltips then
("\n\t\t[ Tooltip.plaintext " ++ valueStr)
++ ("\n\t\t, Tooltip.onHover (OpenTooltip " ++ valueStr ++ ")")
++ ("\n\t\t, Tooltip.open (openTooltip == Just " ++ valueStr ++ ")")
++ "\n\t\t]"
else
"[]"
)
2022-03-29 00:16:34 +03:00
, ", content = text \"...\""
2022-03-25 01:54:46 +03:00
, "}"
]
|> String.join "\n\t "
, { icon = Maybe.map Tuple.second maybeIcon
, label = Html.text label
, value = value
, idString = toLower (Debug.toString value)
, attributes = []
, tabTooltip =
if tooltips then
[ Tooltip.plaintext (Debug.toString value)
, Tooltip.onHover (PageTooltip value)
, Tooltip.open (openTooltip == Just value)
2020-08-05 07:35:10 +03:00
]
2022-03-25 01:54:46 +03:00
else
[]
, content =
if longContent then
Html.div
[ css
[ Css.maxHeight (Css.px 100)
, Css.overflowY Css.auto
]
]
[ Html.p [] [ Html.text <| "Content for " ++ Debug.toString value ]
, Html.ol [] <|
List.map (\i -> Html.li [] [ Html.text (Debug.toString value) ])
(List.range 1 20)
2020-08-05 07:35:10 +03:00
]
2022-03-25 01:54:46 +03:00
else
Html.text <| "Content for " ++ Debug.toString value
}
)
2020-08-05 05:30:24 +03:00
in
2022-03-25 01:54:46 +03:00
[ buildOption Flag ( "UiIcon.flag", UiIcon.flag )
, buildOption Sprout ( "UiIcon.sprout", UiIcon.sprout )
, buildOption Star ( "UiIcon.star", UiIcon.star )
, buildOption Sapling ( "UiIcon.sapling", UiIcon.sapling )
, buildOption Attention ( "UiIcon.attention", Svg.withColor Colors.greenDark UiIcon.attention )
, buildOption Tree ( "UiIcon.tree", UiIcon.tree )
, buildOption Premium ( "UiIcon.premiumLock", UiIcon.premiumLock )
, buildOption Activity ( "UiIcon.activity", Svg.withColor Colors.purple UiIcon.activity )
2020-07-29 21:10:49 +03:00
]
2022-03-25 02:11:53 +03:00
buildRadioOptions : { options | tooltips : Bool } -> Maybe Int -> Content -> List ( String, SegmentedControl.Radio Int Msg )
buildRadioOptions options currentlyHovered content =
2020-08-05 05:06:28 +03:00
let
2022-03-25 02:11:53 +03:00
buildOption : Int -> ( String, Svg ) -> ( String, SegmentedControl.Radio Int Msg )
2021-04-06 23:33:53 +03:00
buildOption value ( text, icon ) =
2020-09-09 00:47:38 +03:00
let
( icon_, label ) =
getIconAndLabel content
icon
2022-03-25 01:54:46 +03:00
("Source " ++ Debug.toString (value + 1))
2020-09-09 00:47:38 +03:00
in
2022-03-25 02:18:21 +03:00
( [ "{ icon = " ++ Debug.toString (Maybe.map (\_ -> "UiIcon." ++ toLower label) icon_)
, ", label = Html.text " ++ label
, ", value = " ++ String.fromInt value
, ", idString = String.fromInt " ++ String.fromInt value
, ", tooltip = "
++ (if options.tooltips then
("\n\t\t[ Tooltip.plaintext " ++ String.fromInt value)
++ ("\n\t\t, Tooltip.onHover (OpenTooltip " ++ String.fromInt value ++ ")")
++ ("\n\t\t, Tooltip.open (openTooltip == Just " ++ String.fromInt value ++ ")")
++ "\n\t\t]"
2022-03-25 02:11:53 +03:00
2022-03-25 02:18:21 +03:00
else
"[]"
)
2022-03-25 02:11:53 +03:00
, ", attributes = []"
, "}"
]
2022-03-25 02:18:21 +03:00
|> String.join "\n\t "
2022-03-25 02:11:53 +03:00
, { icon = icon_
, label = Html.text label
, value = value
, idString = String.fromInt value
, tooltip =
if options.tooltips then
[ Tooltip.plaintext text
, Tooltip.open (currentlyHovered == Just value)
, Tooltip.fitToContent
, Tooltip.onHover
(\hovered ->
HoverRadio
(if hovered then
Just value
2022-03-25 02:11:53 +03:00
else
Nothing
)
)
]
2022-03-25 02:11:53 +03:00
else
[]
, attributes = []
}
)
in
2020-08-05 07:28:01 +03:00
List.indexedMap buildOption
2021-04-06 23:33:53 +03:00
[ ( "Leaderboard", UiIcon.leaderboard )
, ( "Person", UiIcon.person )
, ( "Performance", UiIcon.performance )
, ( "Gift", UiIcon.gift )
, ( "Document", UiIcon.document )
, ( "Key", UiIcon.key )
, ( "Badge", UiIcon.badge )
, ( "Hat", UiIcon.hat )
2020-08-05 07:28:01 +03:00
]
{-| -}
type alias State =
2020-08-05 05:30:24 +03:00
{ page : Page
2020-09-09 00:06:47 +03:00
, pageTooltip : Maybe Page
, optionallySelected : Maybe Int
, optionsControl : Control Options
2021-04-06 23:33:53 +03:00
, radioTooltip : Maybe Int
}
2018-03-24 05:05:34 +03:00
{-| -}
2019-10-24 21:08:28 +03:00
init : State
init =
2020-08-05 05:30:24 +03:00
{ page = Flag
2020-09-09 00:06:47 +03:00
, pageTooltip = Nothing
, optionallySelected = Nothing
, optionsControl = optionsControl
2021-04-06 23:33:53 +03:00
, radioTooltip = Nothing
}
type alias Options =
2022-03-25 01:54:46 +03:00
{ positioning : ( String, SegmentedControl.Positioning )
2020-09-09 00:47:38 +03:00
, content : Content
2020-07-29 21:10:49 +03:00
, count : Int
2020-08-05 07:35:10 +03:00
, longContent : Bool
2020-09-09 00:06:47 +03:00
, tooltips : Bool
2018-03-24 05:05:34 +03:00
}
optionsControl : Control Options
optionsControl =
Control.record Options
2020-08-20 23:58:31 +03:00
|> Control.field "positioning"
(Control.choice
2022-03-25 01:54:46 +03:00
[ ( "Left (FitContent)"
, Control.value
( "SegmentedControl.Left SegmentedControl.FitContent"
, SegmentedControl.Left SegmentedControl.FitContent
)
)
, ( "Left (FillContainer)"
, Control.value
( "SegmentedControl.Left SegmentedControl.FillContainer"
, SegmentedControl.Left SegmentedControl.FillContainer
)
)
, ( "Center"
, Control.value
( "SegmentedControl.Center"
, SegmentedControl.Center
)
)
]
)
2020-09-09 00:47:38 +03:00
|> Control.field "content" controlContent
2020-07-29 21:10:49 +03:00
|> Control.field "count"
(Control.choice
(List.map (\i -> ( String.fromInt i, Control.value i )) (List.range 2 8))
)
2020-08-05 07:35:10 +03:00
|> Control.field "long content" (Control.bool False)
2020-09-09 00:35:36 +03:00
|> Control.field "tooltips" (Control.bool True)
2020-09-09 00:47:38 +03:00
type Content
= TextAndIcon
| Text
| Icon
controlContent : Control Content
controlContent =
Control.choice
[ ( "Text and icon", Control.value TextAndIcon )
, ( "Text", Control.value Text )
, ( "Icon", Control.value Icon )
]
2022-03-25 01:54:46 +03:00
getIconAndLabel : Content -> icon -> String -> ( Maybe icon, String )
2020-09-09 00:47:38 +03:00
getIconAndLabel content icon_ value =
case content of
TextAndIcon ->
( Just icon_, value )
Icon ->
2022-03-25 01:54:46 +03:00
( Just icon_, "" )
2020-09-09 00:47:38 +03:00
Text ->
( Nothing, value )
{-| -}
type Msg
2020-09-09 00:35:36 +03:00
= FocusAndSelectPage { select : Page, focus : Maybe String }
2020-08-06 01:19:09 +03:00
| Focused (Result Dom.Error ())
2020-09-09 00:06:47 +03:00
| PageTooltip Page Bool
2020-08-06 01:25:26 +03:00
| SelectRadio Int
2021-04-06 23:33:53 +03:00
| HoverRadio (Maybe Int)
| ChangeOptions (Control Options)
2018-03-24 05:05:34 +03:00
{-| -}
update : Msg -> State -> ( State, Cmd Msg )
update msg state =
case msg of
2020-09-09 00:35:36 +03:00
FocusAndSelectPage { select, focus } ->
( { state | page = select }
, Maybe.map (Task.attempt Focused << Dom.focus) focus
|> Maybe.withDefault Cmd.none
2020-08-06 01:19:09 +03:00
)
Focused _ ->
( state
, Cmd.none
)
2020-09-09 00:06:47 +03:00
PageTooltip page isOpen ->
( { state
| pageTooltip =
if isOpen then
Just page
else
Nothing
}
, Cmd.none
)
2020-08-06 01:25:26 +03:00
SelectRadio id ->
2020-05-20 21:58:21 +03:00
( { state | optionallySelected = Just id }
, Cmd.none
)
ChangeOptions newOptions ->
( { state | optionsControl = newOptions }
, Cmd.none
)
2021-04-06 23:33:53 +03:00
HoverRadio hovered ->
( { state | radioTooltip = hovered }
, Cmd.none
)