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

352 lines
13 KiB
Elm
Raw Normal View History

2020-05-07 22:46:21 +03:00
module Examples.Menu exposing (Msg, State, example)
{-|
@docs Msg, State, example
-}
import Accessibility.Styled as Html exposing (..)
2021-02-11 03:01:27 +03:00
import Browser.Dom as Dom
2020-05-07 22:46:21 +03:00
import Category exposing (Category(..))
import Css
import Debug.Control as Control exposing (Control)
import EllieLink
2020-05-07 22:46:21 +03:00
import Example exposing (Example)
import Html.Styled.Attributes exposing (css)
2022-03-15 21:06:13 +03:00
import KeyboardSupport exposing (Key(..))
import Nri.Ui.ClickableSvg.V2 as ClickableSvg
import Nri.Ui.ClickableText.V3 as ClickableText
2021-08-28 00:56:17 +03:00
import Nri.Ui.Menu.V3 as Menu
2022-03-15 21:06:13 +03:00
import Nri.Ui.Svg.V1 exposing (Svg)
import Nri.Ui.Tooltip.V2 as Tooltip
import Nri.Ui.UiIcon.V1 as UiIcon
import Set exposing (Set)
2021-02-11 03:01:27 +03:00
import Task
2020-05-07 22:46:21 +03:00
{-| -}
example : Example State Msg
example =
2020-09-09 21:43:10 +03:00
{ name = "Menu"
2021-08-28 00:56:17 +03:00
, version = 3
2020-05-07 22:46:21 +03:00
, state = init
, update = update
, subscriptions = \_ -> Sub.none
2021-11-12 01:54:56 +03:00
, categories = [ Layout ]
, keyboardSupport =
[ { keys = [ Space ], result = "Opens the menu" }
, { keys = [ Enter ], result = "Opens the menu" }
2021-03-18 20:35:46 +03:00
, { keys = [ Tab ], result = "Takes focus out of the menu to the next focusable element & closes the menu." }
, { keys = [ Tab, Shift ], result = "Takes focus out of the menu to the previous focusable element & closes the menu." }
, { keys = [ Arrow KeyboardSupport.Up ]
, result = "If menu is closed, opens the menu & selects the last menu item.\nIf menu is open, moves the focus to the previous menu item."
}
, { keys = [ Arrow KeyboardSupport.Down ]
, result = "If menu is closed, opens the menu & selects the first menu item.\nIf menu is open, moves the focus to the next menu item."
}
, { keys = [ Esc ], result = "Closes the menu" }
]
2021-11-05 21:19:08 +03:00
, preview = []
, view = view
2020-05-07 22:46:21 +03:00
}
view : EllieLink.Config -> State -> List (Html Msg)
view ellieLinkConfig state =
let
viewConfiguration =
Control.currentValue state.viewConfiguration
viewCustomConfiguration =
Control.currentValue state.viewCustomConfiguration
isOpen name =
case state.openMenu of
Just open ->
open == name
Nothing ->
False
in
[ div [ css [ Css.displayFlex, Css.flexWrap Css.wrap ] ]
2021-08-28 00:56:17 +03:00
[ Html.h3 [ css [ Css.width (Css.pct 100) ] ] [ Html.text "Nri.Menu.button" ]
2020-05-07 23:32:30 +03:00
, viewControl SetViewConfiguration state.viewConfiguration
, Menu.view
2021-08-31 07:56:17 +03:00
(List.filterMap identity
[ Just <| Menu.buttonId "1stPeriodEnglish__button"
, Just <| Menu.menuId "1stPeriodEnglish__menu"
, Just <| Menu.alignment viewConfiguration.alignment
, Just <| Menu.isDisabled viewConfiguration.isDisabled
, Maybe.map Menu.menuWidth viewConfiguration.menuWidth
]
2021-08-28 00:56:17 +03:00
)
{ isOpen = isOpen "1stPeriodEnglish"
, focusAndToggle = FocusAndToggle "1stPeriodEnglish"
, entries =
[ Menu.entry "hello-button" <|
\attrs ->
ClickableText.button "Hello"
[ ClickableText.onClick (ConsoleLog "Hello")
, ClickableText.small
, ClickableText.custom attrs
]
, Menu.group "Menu group"
[ Menu.entry "gift-button" <|
2021-02-11 04:53:41 +03:00
\attrs ->
ClickableText.button "Gift"
[ ClickableText.onClick (ConsoleLog "Gift")
2021-02-11 04:53:41 +03:00
, ClickableText.small
, ClickableText.custom attrs
, ClickableText.icon UiIcon.gift
2021-02-11 04:53:41 +03:00
]
, Menu.entry "null-button" <|
2021-02-11 04:53:41 +03:00
\attrs ->
ClickableText.button "Nope!"
[ ClickableText.onClick (ConsoleLog "Nope!")
2021-02-11 04:53:41 +03:00
, ClickableText.small
, ClickableText.custom attrs
, ClickableText.icon UiIcon.null
2021-02-11 04:53:41 +03:00
]
2021-03-05 02:04:05 +03:00
, Menu.entry "no-icon-button" <|
\attrs ->
ClickableText.button "Skip"
[ ClickableText.onClick (ConsoleLog "Skip")
, ClickableText.small
, ClickableText.custom attrs
]
]
2021-03-05 02:04:05 +03:00
, Menu.entry "performance-button" <|
\attrs ->
ClickableText.button "Performance"
[ ClickableText.onClick (ConsoleLog "Performance")
, ClickableText.small
, ClickableText.custom attrs
]
]
2021-08-28 00:56:17 +03:00
, button =
Menu.button
2021-08-31 07:56:17 +03:00
(List.filterMap identity
[ Just <| Menu.hasBorder viewConfiguration.hasBorder
, Just <| Menu.wrapping viewConfiguration.wrapping
, Maybe.map Menu.icon viewConfiguration.icon
, Maybe.map Menu.buttonWidth viewConfiguration.buttonWidth
]
2021-08-28 00:56:17 +03:00
)
"1st Period English with Mx. Trainer"
}
]
, div
[ css [ Css.displayFlex, Css.flexWrap Css.wrap ] ]
2021-08-28 00:56:17 +03:00
[ Html.h3 [ css [ Css.width (Css.pct 100) ] ] [ Html.text "Nri.Menu.custom" ]
, viewControl SetIconButtonWithMenuConfiguration state.viewCustomConfiguration
2021-08-28 00:56:17 +03:00
, Menu.view
2021-08-31 07:56:17 +03:00
(List.filterMap identity
[ Just <| Menu.buttonId "icon-button-with-menu__button"
, Just <| Menu.menuId "icon-button-with-menu__menu"
, Just <| Menu.alignment viewCustomConfiguration.alignment
, Just <| Menu.isDisabled viewCustomConfiguration.isDisabled
, Maybe.map Menu.menuWidth viewCustomConfiguration.menuWidth
]
2021-08-28 00:56:17 +03:00
)
{ entries =
2021-03-18 20:31:40 +03:00
[ Menu.entry "see-more-button" <|
\attrs ->
ClickableText.button "See more"
[ ClickableText.onClick (ConsoleLog "See more")
, ClickableText.small
, ClickableText.custom attrs
, ClickableText.icon UiIcon.seeMore
]
]
2021-08-28 00:56:17 +03:00
, isOpen = isOpen "icon-button-with-menu"
, focusAndToggle = FocusAndToggle "icon-button-with-menu"
, button =
Menu.custom <|
\buttonAttributes ->
Tooltip.view
{ trigger =
\attrs ->
ClickableSvg.button "Menu.viewCustom: Click me!"
viewCustomConfiguration.icon
[ ClickableSvg.disabled viewCustomConfiguration.isDisabled
, ClickableSvg.custom (attrs ++ buttonAttributes)
, ClickableSvg.exactWidth 25
, ClickableSvg.exactHeight 25
, ClickableSvg.css [ Css.marginLeft (Css.px 10) ]
]
, id = "viewCustom-example-tooltip"
}
[ Tooltip.plaintext "Menu.viewCustom: Click me!"
, Tooltip.primaryLabel
, Tooltip.onHover (ShowTooltip "viewCustom")
, Tooltip.open (Set.member "viewCustom" state.openTooltips)
, Tooltip.smallPadding
, Tooltip.fitToContent
]
2021-03-18 20:31:40 +03:00
}
]
]
2020-05-07 23:32:30 +03:00
viewControl : (Control a -> Msg) -> Control a -> Html Msg
viewControl setControl control =
code
[ css [ Css.minWidth (Css.px 300), Css.marginRight (Css.px 20) ] ]
[ Control.view setControl control
|> fromUnstyled
]
2020-05-07 22:46:21 +03:00
{-| -}
init : State
init =
{ openMenu = Nothing
, checkboxChecked = False
, openTooltips = Set.empty
, viewConfiguration = initViewConfiguration
, viewCustomConfiguration = initIconButtonWithMenuConfiguration
}
2020-05-07 22:46:21 +03:00
{-| -}
type alias State =
{ openMenu : Maybe Id
, checkboxChecked : Bool
, openTooltips : Set String
, viewConfiguration : Control ViewConfiguration
, viewCustomConfiguration : Control IconButtonWithMenuConfiguration
}
type alias ViewConfiguration =
{ isDisabled : Bool
, hasBorder : Bool
, alignment : Menu.Alignment
, wrapping : Menu.TitleWrapping
, buttonWidth : Maybe Int
, menuWidth : Maybe Int
, icon : Maybe Svg
}
initViewConfiguration : Control ViewConfiguration
initViewConfiguration =
Control.record ViewConfiguration
|> Control.field "isDisabled" (Control.bool False)
|> Control.field "hasBorder" (Control.bool True)
|> Control.field "alignment"
(Control.choice
[ ( "Right", Control.value Menu.Right )
, ( "Left", Control.value Menu.Left )
]
)
|> Control.field "wrapping"
(Control.choice
[ ( "WrapAndExpandTitle", Control.value Menu.WrapAndExpandTitle )
, ( "TruncateTitle", Control.value Menu.TruncateTitle )
]
)
|> Control.field "buttonWidth"
(Control.maybe False (Control.choice [ ( "220", Control.value 220 ) ]))
|> Control.field "menuWidth"
(Control.maybe False (Control.choice [ ( "180", Control.value 220 ) ]))
|> Control.field "icon"
(Control.maybe False
(Control.choice
[ ( "gift", Control.value UiIcon.gift )
, ( "hat", Control.value UiIcon.hat )
, ( "star", Control.value UiIcon.star )
]
)
)
type alias IconButtonWithMenuConfiguration =
{ isDisabled : Bool
, alignment : Menu.Alignment
, menuWidth : Maybe Int
, icon : Svg
}
initIconButtonWithMenuConfiguration : Control IconButtonWithMenuConfiguration
initIconButtonWithMenuConfiguration =
Control.record IconButtonWithMenuConfiguration
|> Control.field "isDisabled" (Control.bool False)
|> Control.field "alignment"
(Control.choice
[ ( "Left", Control.value Menu.Left )
, ( "Right", Control.value Menu.Right )
]
)
|> Control.field "menuWidth"
(Control.maybe False (Control.choice [ ( "180", Control.value 220 ) ]))
|> Control.field "icon"
(Control.choice
[ ( "edit", Control.value UiIcon.edit )
, ( "share", Control.value UiIcon.share )
, ( "gear", Control.value UiIcon.gear )
]
)
2020-05-07 22:46:21 +03:00
{-| -}
type Msg
= ShowTooltip String Bool
| ConsoleLog String
| SetViewConfiguration (Control ViewConfiguration)
| SetIconButtonWithMenuConfiguration (Control IconButtonWithMenuConfiguration)
| FocusAndToggle String { isOpen : Bool, focus : Maybe String }
2021-02-11 03:01:27 +03:00
| Focused (Result Dom.Error ())
2020-05-07 22:46:21 +03:00
{-| -}
update : Msg -> State -> ( State, Cmd Msg )
update msg state =
case msg of
ShowTooltip key isOpen ->
( { state
| openTooltips =
if isOpen then
Set.insert key state.openTooltips
else
Set.remove key state.openTooltips
}
, Cmd.none
)
ConsoleLog message ->
2022-03-15 21:06:13 +03:00
( Debug.log "Menu Example" message |> always state, Cmd.none )
SetViewConfiguration configuration ->
( { state | viewConfiguration = configuration }, Cmd.none )
SetIconButtonWithMenuConfiguration configuration ->
( { state | viewCustomConfiguration = configuration }, Cmd.none )
FocusAndToggle id { isOpen, focus } ->
( { state
| openMenu =
if isOpen then
Just id
else
Nothing
}
, Maybe.map (\idString -> Task.attempt Focused (Dom.focus idString)) focus
|> Maybe.withDefault Cmd.none
)
2021-02-11 03:01:27 +03:00
Focused _ ->
( state, Cmd.none )
-- INTERNAL
type alias Id =
String