mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-09-11 07:05:38 +03:00
Merge pull request #1657 from NoRedInk/kra-1441-add-caption-option-to-nriuimenu-groups
Add Menu.captionedGroup, text+menu css helpers, example
This commit is contained in:
commit
ebd5f64952
@ -658,7 +658,7 @@ You will need to pass in the first and last focusable element in the dialog cont
|
||||
}
|
||||
, Table.custom
|
||||
{ header = text "Example"
|
||||
, view = \{ name, menuType, entries } -> forcedOpenExample name menuType entries
|
||||
, view = \{ name, attributes, entries } -> forcedOpenExample name attributes entries
|
||||
, width = Css.pct 20
|
||||
, cellStyles =
|
||||
\{ name } ->
|
||||
@ -707,7 +707,7 @@ You will need to pass in the first and last focusable element in the dialog cont
|
||||
}
|
||||
]
|
||||
[ { name = "List of entries"
|
||||
, menuType = Menu.navMenuList
|
||||
, attributes = [ Menu.navMenuList ]
|
||||
, entries =
|
||||
[ Menu.entry "list-of-entries-clickable-text-entry" <|
|
||||
\attributes ->
|
||||
@ -733,7 +733,7 @@ You will need to pass in the first and last focusable element in the dialog cont
|
||||
, about = "Pass any interactive elements in using `Menu.entry`."
|
||||
}
|
||||
, { name = "Grouped entries"
|
||||
, menuType = Menu.navMenuList
|
||||
, attributes = [ Menu.navMenuList ]
|
||||
, entries =
|
||||
[ List.range 1 2
|
||||
|> List.map
|
||||
@ -771,7 +771,7 @@ The structures are recursive and flexible:
|
||||
"""
|
||||
}
|
||||
, { name = "Mix of singular entries and grouped entries"
|
||||
, menuType = Menu.disclosure { lastId = droppedStudentsId }
|
||||
, attributes = [ Menu.disclosure { lastId = droppedStudentsId } ]
|
||||
, entries =
|
||||
[ Menu.entry "grades-and-perf" <|
|
||||
\attributes ->
|
||||
@ -795,26 +795,104 @@ Because `group` and `entry` both result in the same type, individual entries and
|
||||
Please note that depending on the interactive component you select, our composability may not work correctly yet.
|
||||
|
||||
In this realistic example, we can't actually pass the correct attributes to RadioButton or Switch because it will cause the events for those components to be swallowed, rendering them inoperable.
|
||||
"""
|
||||
}
|
||||
, { name = "Custom CSS"
|
||||
, attributes =
|
||||
[ Menu.disclosure { lastId = "which-should-i-choose" }
|
||||
, Menu.menuWidth 350
|
||||
, Menu.menuCss
|
||||
[ Css.padding (Css.px 20)
|
||||
]
|
||||
, Menu.groupContainerCss
|
||||
[ Css.displayFlex
|
||||
, Css.property "gap" "10px"
|
||||
]
|
||||
, Menu.groupTitleCss
|
||||
[ Css.fontSize (Css.px 16)
|
||||
, Css.fontWeight (Css.int 700)
|
||||
, Css.color Colors.gray20
|
||||
]
|
||||
, Menu.groupCaptionCss
|
||||
[ Css.fontSize (Css.px 13)
|
||||
]
|
||||
]
|
||||
, entries =
|
||||
[ Menu.captionedGroup "Quick Write"
|
||||
"Students write independently, without lessons or tips."
|
||||
[ Menu.entry "preview-quick-write" <|
|
||||
\attributes ->
|
||||
ClickableSvg.link "Preview"
|
||||
UiIcon.preview
|
||||
[ ClickableSvg.linkExternal "about:blank"
|
||||
, ClickableSvg.secondary
|
||||
, ClickableSvg.withBorder
|
||||
, ClickableSvg.custom attributes
|
||||
]
|
||||
, Menu.entry "assign-quick-write" <|
|
||||
\attributes ->
|
||||
ClickableSvg.link "Assign"
|
||||
UiIcon.arrowPointingRightThick
|
||||
[ ClickableSvg.linkExternal "about:blank"
|
||||
, ClickableSvg.primary
|
||||
, ClickableSvg.withBorder
|
||||
, ClickableSvg.custom attributes
|
||||
]
|
||||
]
|
||||
, Menu.captionedGroup "Guided Draft"
|
||||
"Students draft with the support of tutorials, models, and targeted tips."
|
||||
[ Menu.entry "preview-guided-draft" <|
|
||||
\attributes ->
|
||||
ClickableSvg.link "Preview"
|
||||
UiIcon.preview
|
||||
[ ClickableSvg.linkExternal "about:blank"
|
||||
, ClickableSvg.secondary
|
||||
, ClickableSvg.withBorder
|
||||
, ClickableSvg.custom attributes
|
||||
]
|
||||
, Menu.entry "assign-guided-draft" <|
|
||||
\attributes ->
|
||||
ClickableSvg.link "Assign"
|
||||
UiIcon.arrowPointingRightThick
|
||||
[ ClickableSvg.linkExternal "about:blank"
|
||||
, ClickableSvg.primary
|
||||
, ClickableSvg.withBorder
|
||||
, ClickableSvg.custom attributes
|
||||
]
|
||||
]
|
||||
, Menu.entry "which-should-i-choose" <|
|
||||
\attributes ->
|
||||
ClickableText.link "Which should I choose?"
|
||||
[ ClickableText.linkExternal "about:blank"
|
||||
, ClickableText.icon UiIcon.help
|
||||
, ClickableText.custom attributes
|
||||
]
|
||||
]
|
||||
, about = """
|
||||
Each container can be styled with CSS to achieve the desired layout.
|
||||
|
||||
In this example, we use `Menu.menuCss` to reduce the menu padding, `Menu.groupContainerCss` to layout horizontally, and `Menu.groupTitleCss` and `Menu.groupCaptionCss` to style typography.
|
||||
"""
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
forcedOpenExample : String -> Menu.Attribute Msg -> List (Menu.Entry Msg) -> Html Msg
|
||||
forcedOpenExample name type_ =
|
||||
forcedOpenExample : String -> List (Menu.Attribute Msg) -> List (Menu.Entry Msg) -> Html Msg
|
||||
forcedOpenExample name attributes =
|
||||
Menu.view (FocusAndToggle name)
|
||||
[ Menu.clickableSvgWithoutIndicator (name ++ " example")
|
||||
([ Menu.clickableSvgWithoutIndicator (name ++ " example")
|
||||
UiIcon.arrowDown
|
||||
[ ClickableSvg.exactSize 15
|
||||
, ClickableSvg.css [ Css.marginLeft (Css.px 17) ]
|
||||
]
|
||||
, Menu.isOpen True
|
||||
, Menu.buttonId (forcedOpenExampleButtonId name)
|
||||
, Menu.menuId (safeIdWithPrefix name "menuId")
|
||||
, Menu.alignLeft
|
||||
, type_
|
||||
]
|
||||
, Menu.isOpen True
|
||||
, Menu.buttonId (forcedOpenExampleButtonId name)
|
||||
, Menu.menuId (safeIdWithPrefix name "menuId")
|
||||
, Menu.alignLeft
|
||||
]
|
||||
++ attributes
|
||||
)
|
||||
|
||||
|
||||
forcedOpenExampleButtonId : String -> String
|
||||
|
@ -8,8 +8,8 @@ module Nri.Ui.Menu.V4 exposing
|
||||
, navMenuList, disclosure, dialog
|
||||
, menuWidth, menuId, menuZIndex
|
||||
, alignLeft, alignRight
|
||||
, containerCss, groupContainerCss, entryContainerCss
|
||||
, Entry, group, entry
|
||||
, containerCss, menuCss, groupContainerCss, entryContainerCss, groupTitleCss, groupCaptionCss
|
||||
, Entry, group, captionedGroup, entry
|
||||
)
|
||||
|
||||
{-| Patch changes:
|
||||
@ -19,7 +19,9 @@ module Nri.Ui.Menu.V4 exposing
|
||||
- Adjust disabled styles
|
||||
- when the Menu is a dialog or disclosure, _don't_ add role menuitem to the entries
|
||||
- Use ClickableText.medium as the default size when the trigger is `Menu.clickableText`
|
||||
- Adds containerCss, groupContainerCss, and entryContainerCss to customize the style of the respective containers
|
||||
- Adds containerCss, menuCss, groupContainerCss, and entryContainerCss to customize the style of the respective containers
|
||||
- Adds captionedGroup to create a group with a caption
|
||||
- Adds groupTitleCss and groupCaptionCss to customize the style of the group title and caption
|
||||
|
||||
Changes from V3:
|
||||
|
||||
@ -53,12 +55,12 @@ A togglable menu view and related buttons.
|
||||
@docs navMenuList, disclosure, dialog
|
||||
@docs menuWidth, menuId, menuZIndex
|
||||
@docs alignLeft, alignRight
|
||||
@docs containerCss, groupContainerCss, entryContainerCss
|
||||
@docs containerCss, menuCss, groupContainerCss, entryContainerCss, groupTitleCss, groupCaptionCss
|
||||
|
||||
|
||||
## Menu content
|
||||
|
||||
@docs Entry, group, entry
|
||||
@docs Entry, group, captionedGroup, entry
|
||||
|
||||
-}
|
||||
|
||||
@ -70,15 +72,18 @@ import Html.Styled as Html exposing (..)
|
||||
import Html.Styled.Attributes as Attributes exposing (class, classList, css)
|
||||
import Html.Styled.Events as Events
|
||||
import Json.Decode
|
||||
import Maybe.Extra as Maybe
|
||||
import Nri.Ui.AnimatedIcon.V1 as AnimatedIcon
|
||||
import Nri.Ui.Button.V10 as Button
|
||||
import Nri.Ui.ClickableSvg.V2 as ClickableSvg
|
||||
import Nri.Ui.ClickableText.V4 as ClickableText
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Fonts.V1
|
||||
import Nri.Ui.Html.Attributes.V2 as AttributesExtra
|
||||
import Nri.Ui.Html.Attributes.V2 as AttributesExtra exposing (safeId)
|
||||
import Nri.Ui.Html.V3 exposing (viewJust)
|
||||
import Nri.Ui.Shadows.V1 as Shadows
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
import Nri.Ui.Tooltip.V3 as Tooltip
|
||||
import Nri.Ui.WhenFocusLeaves.V2 as WhenFocusLeaves
|
||||
|
||||
@ -101,8 +106,11 @@ type alias MenuConfig msg =
|
||||
, purpose : Purpose
|
||||
, tooltipAttributes : List (Tooltip.Attribute msg)
|
||||
, containerCss : List Style
|
||||
, menuCss : List Style
|
||||
, groupContainerCss : List Style
|
||||
, entryContainerCss : List Style
|
||||
, groupTitleCss : List Style
|
||||
, groupCaptionCss : List Style
|
||||
}
|
||||
|
||||
|
||||
@ -120,8 +128,11 @@ defaultConfig =
|
||||
, purpose = NavMenu
|
||||
, tooltipAttributes = []
|
||||
, containerCss = []
|
||||
, menuCss = []
|
||||
, groupContainerCss = []
|
||||
, entryContainerCss = []
|
||||
, groupTitleCss = []
|
||||
, groupCaptionCss = []
|
||||
}
|
||||
|
||||
|
||||
@ -170,6 +181,13 @@ containerCss styles =
|
||||
Attribute <| \config -> { config | containerCss = config.containerCss ++ styles }
|
||||
|
||||
|
||||
{-| Adds CSS to the content of the menu. This will style the menu itself.
|
||||
-}
|
||||
menuCss : List Css.Style -> Attribute msg
|
||||
menuCss styles =
|
||||
Attribute <| \config -> { config | menuCss = config.menuCss ++ styles }
|
||||
|
||||
|
||||
{-| Adds CSS to the element containing the group. This will style items created via Menu.group
|
||||
-}
|
||||
groupContainerCss : List Css.Style -> Attribute msg
|
||||
@ -184,6 +202,20 @@ entryContainerCss styles =
|
||||
Attribute <| \config -> { config | entryContainerCss = config.entryContainerCss ++ styles }
|
||||
|
||||
|
||||
{-| Adds CSS to the element containing the group title. This will style the title of items created via Menu.group
|
||||
-}
|
||||
groupTitleCss : List Css.Style -> Attribute msg
|
||||
groupTitleCss styles =
|
||||
Attribute <| \config -> { config | groupTitleCss = config.groupTitleCss ++ styles }
|
||||
|
||||
|
||||
{-| Adds CSS to the element containing the group caption. This will style the caption of items created via Menu.captionedGroup
|
||||
-}
|
||||
groupCaptionCss : List Css.Style -> Attribute msg
|
||||
groupCaptionCss styles =
|
||||
Attribute <| \config -> { config | groupCaptionCss = config.groupCaptionCss ++ styles }
|
||||
|
||||
|
||||
{-| Whether the menu is open
|
||||
-}
|
||||
isOpen : Bool -> Attribute msg
|
||||
@ -299,14 +331,21 @@ view focusAndToggle attributes entries =
|
||||
-}
|
||||
type Entry msg
|
||||
= Single String (List (Html.Attribute msg) -> Html msg)
|
||||
| Batch String (List (Entry msg))
|
||||
| Batch String (Maybe String) (List (Entry msg))
|
||||
|
||||
|
||||
{-| Represents a group of entries with a named legend.
|
||||
-}
|
||||
group : String -> List (Entry msg) -> Entry msg
|
||||
group legendName entries =
|
||||
Batch legendName entries
|
||||
Batch legendName Nothing entries
|
||||
|
||||
|
||||
{-| Represents a group of entries with a named legend and text caption.
|
||||
-}
|
||||
captionedGroup : String -> String -> List (Entry msg) -> Entry msg
|
||||
captionedGroup legendName caption entries =
|
||||
Batch legendName (Just caption) entries
|
||||
|
||||
|
||||
{-| Represents a single **focusable** entry.
|
||||
@ -678,7 +717,7 @@ getFirstIds entries =
|
||||
Single idString _ ->
|
||||
Just idString
|
||||
|
||||
Batch _ es ->
|
||||
Batch _ _ es ->
|
||||
Maybe.andThen getIdString (List.head es)
|
||||
in
|
||||
List.filterMap getIdString entries
|
||||
@ -692,7 +731,7 @@ getLastIds entries =
|
||||
Single idString _ ->
|
||||
Just idString
|
||||
|
||||
Batch _ es ->
|
||||
Batch _ _ es ->
|
||||
Maybe.andThen getIdString (List.head (List.reverse es))
|
||||
in
|
||||
List.filterMap getIdString (List.reverse entries)
|
||||
@ -790,15 +829,35 @@ viewEntry config focusAndToggle { upId, downId, entry_ } =
|
||||
]
|
||||
]
|
||||
|
||||
Batch title childList ->
|
||||
Batch title caption childList ->
|
||||
let
|
||||
captionId =
|
||||
safeId (title ++ "--caption")
|
||||
in
|
||||
case childList of
|
||||
[] ->
|
||||
Html.text ""
|
||||
|
||||
_ ->
|
||||
fieldset (styleGroupContainer config.groupContainerCss) <|
|
||||
legend styleGroupTitle
|
||||
[ span (styleGroupTitleText config) [ Html.text title ] ]
|
||||
div [ css [ flexGrow (int 1) ] ]
|
||||
[ legend styleGroupTitle
|
||||
[ span
|
||||
(styleGroupTitleText config
|
||||
|> Maybe.cons (Maybe.map (always (Aria.describedBy [ captionId ])) caption)
|
||||
)
|
||||
[ Html.text title ]
|
||||
]
|
||||
, viewJust
|
||||
(\c ->
|
||||
Text.caption
|
||||
[ Text.plaintext c
|
||||
, Text.id captionId
|
||||
, Text.css <| styleGroupCaption config
|
||||
]
|
||||
)
|
||||
caption
|
||||
]
|
||||
:: viewEntries config
|
||||
{ focusAndToggle = focusAndToggle
|
||||
, previousId = upId
|
||||
@ -845,14 +904,20 @@ styleGroupTitle =
|
||||
styleGroupTitleText : MenuConfig msg -> List (Html.Attribute msg)
|
||||
styleGroupTitleText config =
|
||||
[ class "GroupTitleText"
|
||||
, css
|
||||
, css <|
|
||||
[ backgroundColor Colors.white
|
||||
, zIndex (int <| config.zIndex + 1)
|
||||
, position relative
|
||||
]
|
||||
++ config.groupTitleCss
|
||||
]
|
||||
|
||||
|
||||
styleGroupCaption : MenuConfig msg -> List Style
|
||||
styleGroupCaption config =
|
||||
paddingTop (px 2) :: config.groupCaptionCss
|
||||
|
||||
|
||||
styleGroupContainer : List Style -> List (Html.Attribute msg)
|
||||
styleGroupContainer styles =
|
||||
[ class "GroupContainer"
|
||||
@ -885,7 +950,7 @@ styleOuterContent _ config =
|
||||
|
||||
styleContent : Bool -> MenuConfig msg -> Html.Attribute msg
|
||||
styleContent contentVisible config =
|
||||
css
|
||||
css <|
|
||||
[ padding (px 25)
|
||||
, margin zero
|
||||
, border3 (px 1) solid Colors.gray85
|
||||
@ -927,6 +992,7 @@ styleContent contentVisible config =
|
||||
else
|
||||
display Css.none
|
||||
]
|
||||
++ config.menuCss
|
||||
|
||||
|
||||
styleContainer : List Style -> List (Html.Attribute msg)
|
||||
|
Loading…
Reference in New Issue
Block a user