From 91b87b7ec8324c12ca053ce3441ecafb990c24f7 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Wed, 5 May 2021 16:03:57 -0700 Subject: [PATCH 1/4] Update to Accordion V3 version --- elm.json | 1 + src/Nri/Ui/Accordion/V3.elm | 386 ++++++++++++++++++++++++++ styleguide-app/Examples/Accordion.elm | 261 +++++++++++------ 3 files changed, 556 insertions(+), 92 deletions(-) create mode 100644 src/Nri/Ui/Accordion/V3.elm diff --git a/elm.json b/elm.json index 130a2711..40e06588 100644 --- a/elm.json +++ b/elm.json @@ -8,6 +8,7 @@ "Nri.Ui", "Nri.Ui.Accordion.V1", "Nri.Ui.Accordion.V2", + "Nri.Ui.Accordion.V3", "Nri.Ui.AssetPath", "Nri.Ui.AssignmentIcon.V2", "Nri.Ui.Button.V10", diff --git a/src/Nri/Ui/Accordion/V3.elm b/src/Nri/Ui/Accordion/V3.elm new file mode 100644 index 00000000..9215ccf7 --- /dev/null +++ b/src/Nri/Ui/Accordion/V3.elm @@ -0,0 +1,386 @@ +module Nri.Ui.Accordion.V3 exposing + ( view, HeaderLevel(..) + , AccordionEntry(..), Entry + , StyleOptions, styleAccordion + ) + +{-| + + +## Changes from V2 + + - Do not render collapsed content + - Allow disclosure indicator to be top-aligned + - Allow fully-customizable carets + - Removes as many default styles as possible + - Change header resets to inline styles + - Replace custom passed-in styles with a class-based styling approach (for performance reasons -- getting elm-css class names is too slow.) + - Prevent default browser event on arrow keys (so that the page doesn't scroll when the focus changes) + - Support multiple levels of accordions + + +## Example + + import Nri.Ui.DisclosureIndicator.V2 as DisclosureIndicator + + view : Model -> Html Msg + view model = + div [] + [ Accordion.view + { entries = + [ AccordionEntry + { caret = \isOpen -> DisclosureIndicator.large [ marginRight (px 8) ] isOpen + , content = \() -> text "Accordion Content" + , entryClass = "a-class-distinguishing-this-accordion-from-others-on-the-page" + , headerContent = text "Accordion Header" + , headerId = "a-unique-id-for-this-accordion-header-button" + , headerLevel = Accordion.H1 + , isExpanded = model.isAccordionOpen + , toggle = Just ToggleAccordion + } + [] + ] + , focus = Focus + } + , Accordion.styleAccordion + { entryStyles = [] + , entryExpandedStyles = [] + , entryClosedStyles = [] + , headerStyles = [] + , headerExpandedStyles = [] + , headerClosedStyles = [] + , contentStyles = [] + } + ] + +@docs view, HeaderLevel +@docs AccordionEntry, Entry +@docs StyleOptions, styleAccordion + +-} + +import Accessibility.Styled exposing (Attribute, Html, button, div, section, text) +import Accessibility.Styled.Aria as Aria +import Accessibility.Styled.Key as Key +import Accessibility.Styled.Role as Role +import Accessibility.Styled.Widget as Widget +import Css exposing (..) +import Css.Global +import Html.Styled.Attributes as Attributes +import Html.Styled.Events as Events exposing (onClick) +import Html.Styled.Keyed +import Json.Decode as Decode +import Nri.Ui.Colors.V1 as Colors +import Nri.Ui.Fonts.V1 as Fonts +import Nri.Ui.Html.Attributes.V2 as AttributesExtra + + +{-| -} +type alias StyleOptions = + { entryStyles : List Style + , entryExpandedStyles : List Style + , entryClosedStyles : List Style + , headerStyles : List Style + , headerExpandedStyles : List Style + , headerClosedStyles : List Style + , contentStyles : List Style + } + + +{-| -} +styleAccordion : StyleOptions -> Html msg +styleAccordion styleOptions = + Css.Global.global + [ Css.Global.class accordionHeaderClass + [ margin zero, padding zero ] + , Css.Global.class accordionEntryHeaderClass + ([ displayFlex + , alignItems center + , boxSizing borderBox + , minWidth (pct 100) + + -- button resets + , Css.Global.withAttribute "aria-disabled=false" [ cursor pointer ] + , Css.backgroundColor Css.unset + , borderWidth Css.zero + , margin zero + + -- fonts & text + , textAlign left + , Fonts.baseFont + , fontSize (px 16) + , fontWeight (int 600) + , lineHeight (num 1.2) + , Css.Global.withClass accordionEntryHeaderExpandedClass + styleOptions.headerExpandedStyles + , Css.Global.withClass accordionEntryHeaderCollapsedClass + styleOptions.headerClosedStyles + ] + ++ styleOptions.headerStyles + ) + , Css.Global.class accordionEntryClass + ([ marginBottom (px 10) + , Css.Global.withClass accordionEntryExpandedClass + styleOptions.entryExpandedStyles + , Css.Global.withClass accordionEntryCollapsedClass + styleOptions.entryClosedStyles + ] + ++ styleOptions.entryStyles + ) + , Css.Global.class accordionEntryPanelClass + styleOptions.contentStyles + ] + + +accordionClass : String +accordionClass = + "accordion-v3" + + +accordionHeaderClass : String +accordionHeaderClass = + "accordion-v3-header" + + +accordionEntryHeaderClass : String +accordionEntryHeaderClass = + "accordion-v3-entry-header" + + +accordionEntryHeaderExpandedClass : String +accordionEntryHeaderExpandedClass = + "accordion-v3-entry-header-expanded" + + +accordionEntryHeaderCollapsedClass : String +accordionEntryHeaderCollapsedClass = + "accordion-v3-entry-header-collapsed" + + +accordionEntryClass : String +accordionEntryClass = + "accordion-v3-entry" + + +accordionEntryExpandedClass : String +accordionEntryExpandedClass = + "accordion-v3-entry-state-expanded" + + +accordionEntryCollapsedClass : String +accordionEntryCollapsedClass = + "accordion-v3-entry-state-collapsed" + + +accordionEntryPanelClass : String +accordionEntryPanelClass = + "accordion-v3-entry-panel" + + +{-| Corresponds to h1, h2, h3 etc. +Choose the correct header level given your page context. +-} +type HeaderLevel + = H1 + | H2 + | H3 + | H4 + | H5 + | H6 + + +header : HeaderLevel -> Html msg -> Html msg +header headerLevel content = + case headerLevel of + H1 -> + Accessibility.Styled.h1 [ Attributes.class accordionHeaderClass ] [ content ] + + H2 -> + Accessibility.Styled.h2 [ Attributes.class accordionHeaderClass ] [ content ] + + H3 -> + Accessibility.Styled.h3 [ Attributes.class accordionHeaderClass ] [ content ] + + H4 -> + Accessibility.Styled.h4 [ Attributes.class accordionHeaderClass ] [ content ] + + H5 -> + Accessibility.Styled.h5 [ Attributes.class accordionHeaderClass ] [ content ] + + H6 -> + Accessibility.Styled.h6 [ Attributes.class accordionHeaderClass ] [ content ] + + +{-| -} +type AccordionEntry msg + = AccordionEntry (Entry msg) (List (AccordionEntry msg)) + + +{-| -} +type alias Entry msg = + { caret : Bool -> Html msg + , content : () -> Html msg + , entryClass : String + , headerContent : Html msg + , headerId : String + , headerLevel : HeaderLevel + , isExpanded : Bool + , toggle : Maybe (Bool -> msg) + } + + +getHeaderId : AccordionEntry msg -> String +getHeaderId entry = + case entry of + AccordionEntry { headerId } _ -> + headerId + + +{-| -} +view : + { entries : List (AccordionEntry msg) + , focus : String -> msg + } + -> Html msg +view { entries, focus } = + view_ + { entries = entries + , focus = focus + , leftId = Nothing + } + + +view_ : + { entries : List (AccordionEntry msg) + , focus : String -> msg + , leftId : Maybe String + } + -> Html msg +view_ { entries, focus, leftId } = + let + headerIds : List String + headerIds = + List.map getHeaderId entries + + arrowUpIds : List (Maybe String) + arrowUpIds = + lastHeaderId :: List.map Just headerIds + + firstHeaderId : Maybe String + firstHeaderId = + List.head headerIds + + lastHeaderId : Maybe String + lastHeaderId = + List.head (List.reverse headerIds) + in + div + [ Attributes.class accordionClass + , Attributes.attribute "aria-live" "polite" + ] + [ Html.Styled.Keyed.node "div" + [] + (entries + |> List.map2 (\id nextEntry -> ( id, nextEntry )) arrowUpIds + |> List.foldr + (\( previousId, AccordionEntry entry_ children ) ( nextId, acc ) -> + let + node = + ( "keyed-section__" ++ entry_.headerId + , viewEntry focus + { up = previousId + , down = nextId + , right = Maybe.map getHeaderId (List.head children) + , left = leftId + } + entry_ + children + ) + in + ( Just entry_.headerId + , node :: acc + ) + ) + ( firstHeaderId, [] ) + |> Tuple.second + ) + ] + + +viewEntry : + (String -> msg) + -> + { up : Maybe String + , down : Maybe String + , right : Maybe String + , left : Maybe String + } + -> Entry msg + -> List (AccordionEntry msg) + -> Html msg +viewEntry focus arrows ({ headerId, headerLevel, caret, headerContent, entryClass, content, isExpanded } as config) children = + let + panelId = + "accordion-panel__" ++ headerId + in + div + [ Attributes.classList + [ ( accordionEntryClass, True ) + , ( entryClass, True ) + , ( accordionEntryExpandedClass, isExpanded ) + , ( accordionEntryCollapsedClass, not isExpanded ) + ] + ] + [ header headerLevel <| + button + [ Attributes.id headerId + , Attributes.classList + [ ( accordionEntryHeaderClass, True ) + , ( entryClass, True ) + , ( accordionEntryHeaderExpandedClass, isExpanded ) + , ( accordionEntryHeaderCollapsedClass, not isExpanded ) + ] + , Widget.disabled (config.toggle == Nothing) + , Widget.expanded isExpanded + , Aria.controls panelId + , config.toggle + |> Maybe.map (\toggle -> onClick (toggle (not isExpanded))) + |> Maybe.withDefault AttributesExtra.none + , Events.custom "keydown" + ([ Maybe.map (\id -> Key.up (focus id)) arrows.up + , Maybe.map (\id -> Key.down (focus id)) arrows.down + , Maybe.map (\id -> Key.right (focus id)) arrows.right + , Maybe.map (\id -> Key.left (focus id)) arrows.left + ] + |> List.filterMap identity + |> Decode.oneOf + |> Decode.map + (\event -> + { message = event + , stopPropagation = False + , preventDefault = True + } + ) + ) + ] + [ caret isExpanded + , headerContent + ] + , section + [ Attributes.id panelId + , Aria.labelledBy headerId + , Attributes.classList + [ ( accordionEntryPanelClass, True ) + , ( entryClass, True ) + ] + , Attributes.hidden (not isExpanded) + ] + (if isExpanded then + [ content () + , view_ { focus = focus, entries = children, leftId = Just headerId } + ] + + else + [] + ) + ] diff --git a/styleguide-app/Examples/Accordion.elm b/styleguide-app/Examples/Accordion.elm index 0945a41a..5ccf0638 100644 --- a/styleguide-app/Examples/Accordion.elm +++ b/styleguide-app/Examples/Accordion.elm @@ -14,16 +14,21 @@ import AtomicDesignType exposing (AtomicDesignType(..)) import Browser.Dom as Dom import Category exposing (Category(..)) import Css exposing (..) -import Dict exposing (Dict) +import Css.Global import Example exposing (Example) import Html.Styled as Html exposing (Html) import Html.Styled.Attributes exposing (css) import KeyboardSupport exposing (Direction(..), Key(..)) -import Nri.Ui.Accordion.V2 as Accordion +import Nri.Ui.Accordion.V3 as Accordion exposing (AccordionEntry(..)) +import Nri.Ui.Colors.Extra as ColorsExtra import Nri.Ui.Colors.V1 as Colors +import Nri.Ui.DisclosureIndicator.V2 as DisclosureIndicator import Nri.Ui.Fonts.V1 as Fonts import Nri.Ui.Heading.V2 as Heading +import Nri.Ui.Svg.V1 as Svg import Nri.Ui.Text.V4 as Text +import Nri.Ui.UiIcon.V1 as UiIcon +import Set exposing (Set) import Task @@ -31,7 +36,7 @@ import Task example : Example State Msg example = { name = "Accordion" - , version = 2 + , version = 3 , state = init , update = update , subscriptions = \_ -> Sub.none @@ -45,6 +50,12 @@ example = , { keys = [ Arrow KeyboardSupport.Down ] , result = "Moves the focus to the next accordion header button (wraps focus to the first header button)" } + , { keys = [ Arrow KeyboardSupport.Right ] + , result = "Moves the focus to the first accordion header button in a nested list of accordions" + } + , { keys = [ Arrow KeyboardSupport.Left ] + , result = "Moves the focus to the parent accordion header button from a a nested accordion" + } ] } @@ -52,89 +63,155 @@ example = {-| -} view : State -> List (Html Msg) view model = - [ Heading.h3 [] [ Html.text "Accordion.view with default styles" ] + let + defaultCaret = + DisclosureIndicator.large [ Css.marginRight (Css.px 8) ] + + defaultClass = + "first-accordion-example" + in + [ Heading.h3 [] [ Html.text "Accordion.view" ] , Accordion.view { entries = - [ { id = 1, title = "Entry 1", content = "Content for the first accordion" } - , { id = 2, title = "Entry 2", content = "Content for the second accordion" } - , { id = 3, title = "Super long entry that is very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long", content = "Content for the third accordion" } - ] - |> List.map - (\entry -> - { headerId = "accordion-entry__" ++ String.fromInt entry.id - , entry = entry - , isExpanded = Dict.get entry.id model |> Maybe.withDefault False - } - ) - , headerLevel = Accordion.H4 - , viewHeader = .title >> Html.text - , viewContent = \{ content } -> Text.smallBody [ Html.text content ] - , customStyles = Nothing - , toggle = \entry toExpand -> Toggle entry.id toExpand - , focus = Focus - , caret = Accordion.DefaultCaret - } - , Heading.h3 [] [ Html.text "Accordion.view with custom styles from peer reviews" ] - , Accordion.view - { entries = - [ { id = 4 - , title = "Firstname Lastname" - , content = - Html.div - [ css [ Fonts.baseFont, fontSize (px 13) ] - ] - [ Html.text "has not started writing" ] - } - , { id = 5 - , title = "LongFirstnameAnd EvenLongerLastname" - , content = - Html.div - [ css [ Fonts.baseFont, fontSize (px 13) ] ] - [ Html.text "has started writing" ] - } - ] - |> List.map - (\entry -> - { headerId = "accordion-entry__" ++ String.fromInt entry.id - , entry = entry - , isExpanded = Dict.get entry.id model |> Maybe.withDefault False - } - ) - , headerLevel = Accordion.H4 - , viewHeader = .title >> Html.text - , viewContent = .content - , customStyles = - Just - (\_ -> - { entryStyles = - [ borderTop3 (px 1) solid Colors.gray75 - , marginBottom zero - , width (px 284) - ] - , entryExpandedStyles = [] - , entryClosedStyles = [] - , headerStyles = - [ height (px 46) - , paddingLeft (px 8) - , paddingRight (px 8) - , Css.alignItems Css.center - ] - , headerExpandedStyles = - [ backgroundColor Colors.gray96 - , borderRadius zero - ] - , headerClosedStyles = [ backgroundColor transparent ] - , contentStyles = - [ backgroundColor Colors.gray96 - , paddingLeft (px 8) - , paddingRight (px 8) - , paddingBottom (px 8) - ] + [ AccordionEntry + { caret = defaultCaret + , content = \_ -> Html.text "Content for the first accordion" + , entryClass = defaultClass + , headerContent = Html.text "Default Look" + , headerId = "accordion-entry__1" + , headerLevel = Accordion.H4 + , isExpanded = Set.member 1 model + , toggle = Just (Toggle 1) + } + [ AccordionEntry + { caret = defaultCaret + , content = \_ -> Html.text "Content for the Accordion Child" + , entryClass = defaultClass + , headerContent = Html.text "Accordion Child" + , headerId = "accordion-entry__2" + , headerLevel = Accordion.H5 + , isExpanded = Set.member 2 model + , toggle = Just (Toggle 2) } - ) - , toggle = \entry toExpand -> Toggle entry.id toExpand + [] + ] + , AccordionEntry + { caret = + \isOpen -> + UiIcon.seeMore + |> Svg.withWidth (Css.px 17) + |> Svg.withHeight (Css.px 17) + |> Svg.withCss [ Css.marginRight (Css.px 8) ] + |> Svg.withColor + (if isOpen then + Colors.azureDark + + else + Colors.azure + ) + |> Svg.toHtml + , content = \_ -> Html.text "Content for the third accordion" + , entryClass = defaultClass + , headerContent = Html.text "Custom Carets!" + , headerId = "accordion-entry__3" + , headerLevel = Accordion.H4 + , isExpanded = Set.member 3 model + , toggle = Just (Toggle 3) + } + [] + , AccordionEntry + { caret = + \_ -> + UiIcon.null + |> Svg.withWidth (Css.px 17) + |> Svg.withHeight (Css.px 17) + |> Svg.withCss [ Css.marginRight (Css.px 8) ] + |> Svg.withColor Colors.gray85 + |> Svg.toHtml + , content = \_ -> Html.text "Content for the fourth accordion" + , entryClass = defaultClass + , headerContent = Html.text "This accordion can't be opened." + , headerId = "accordion-entry__4" + , headerLevel = Accordion.H5 + , isExpanded = Set.member 4 model + , toggle = Nothing + } + [] + , AccordionEntry + { caret = + \_ -> + UiIcon.null + |> Svg.withWidth (Css.px 17) + |> Svg.withHeight (Css.px 17) + |> Svg.withCss [ Css.marginRight (Css.px 8) ] + |> Svg.withColor Colors.gray85 + |> Svg.toHtml + , content = \_ -> Html.text "Content for the fifth accordion" + , entryClass = defaultClass + , headerContent = Html.text "This accordion can't be closed." + , headerId = "accordion-entry__5" + , headerLevel = Accordion.H5 + , isExpanded = True + , toggle = Nothing + } + [] + , AccordionEntry + { caret = defaultCaret + , content = + \_ -> + Html.div + [ css + [ Css.backgroundColor Colors.gray92 + , Css.minHeight (Css.vh 100) + , Css.padding (Css.px 20) + ] + ] + [ Html.text "Content for the accordion" + ] + , entryClass = "fixed-positioning-accordion-example" + , headerContent = Html.text "Fixed Position Example: Expand & Scroll!" + , headerId = "accordion-entry__6" + , headerLevel = Accordion.H4 + , isExpanded = Set.member 6 model + , toggle = Just (Toggle 6) + } + [] + ] , focus = Focus - , caret = Accordion.DefaultCaret + } + , Accordion.styleAccordion + { entryStyles = + [ Css.marginLeft (Css.px 16) + , Css.Global.withClass "fixed-positioning-accordion-example" + [ Css.position Css.relative + ] + ] + , entryExpandedStyles = + [ Css.Global.withClass "fixed-positioning-accordion-example" + [ Css.Global.children + [ Css.Global.h4 + [ Css.position Css.sticky + , Css.property "position" "-webkit-sticky" + , Css.top (Css.px -8) + ] + ] + ] + ] + , entryClosedStyles = [] + , headerStyles = + [ Css.Global.withClass "fixed-positioning-accordion-example" + [ Css.padding (Css.px 20) + ] + ] + , headerExpandedStyles = + [ Css.Global.withClass "fixed-positioning-accordion-example" + [ Css.backgroundColor Colors.gray96 + , Css.borderRadius (Css.px 8) + , Css.boxShadow5 Css.zero Css.zero (px 10) zero (ColorsExtra.withAlpha 0.2 Colors.gray20) + ] + ] + , headerClosedStyles = [] + , contentStyles = [] } ] @@ -148,26 +225,26 @@ type Msg {-| -} init : State init = - Dict.fromList - [ ( 1, False ) - , ( 2, False ) - , ( 3, False ) - , ( 4, False ) - , ( 5, False ) - ] + Set.empty {-| -} type alias State = - Dict Int Bool + Set Int {-| -} update : Msg -> State -> ( State, Cmd Msg ) update msg model = case msg of - Toggle id toExpanded -> - ( Dict.insert id toExpanded model, Cmd.none ) + Toggle id expand -> + ( if expand then + Set.insert id model + + else + Set.remove id model + , Cmd.none + ) Focus id -> ( model, Task.attempt Focused (Dom.focus id) ) From c28e4e8a18403afa04a184015c5a33b118f01078 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Wed, 5 May 2021 16:28:42 -0700 Subject: [PATCH 2/4] Make the examples a bit more standardized. Incorporating everything that the accordion might support made loking at the example confusing --- styleguide-app/Examples/Accordion.elm | 135 ++++++++++++++------------ 1 file changed, 73 insertions(+), 62 deletions(-) diff --git a/styleguide-app/Examples/Accordion.elm b/styleguide-app/Examples/Accordion.elm index 5ccf0638..4aa37583 100644 --- a/styleguide-app/Examples/Accordion.elm +++ b/styleguide-app/Examples/Accordion.elm @@ -10,14 +10,14 @@ module Examples.Accordion exposing -} +import Accessibility.Styled as Html exposing (Html) import AtomicDesignType exposing (AtomicDesignType(..)) import Browser.Dom as Dom import Category exposing (Category(..)) import Css exposing (..) import Css.Global import Example exposing (Example) -import Html.Styled as Html exposing (Html) -import Html.Styled.Attributes exposing (css) +import Html.Styled.Attributes as Attributes exposing (css, src) import KeyboardSupport exposing (Direction(..), Key(..)) import Nri.Ui.Accordion.V3 as Accordion exposing (AccordionEntry(..)) import Nri.Ui.Colors.Extra as ColorsExtra @@ -67,7 +67,7 @@ view model = defaultCaret = DisclosureIndicator.large [ Css.marginRight (Css.px 8) ] - defaultClass = + entryClass = "first-accordion-example" in [ Heading.h3 [] [ Html.text "Accordion.view" ] @@ -75,9 +75,9 @@ view model = { entries = [ AccordionEntry { caret = defaultCaret - , content = \_ -> Html.text "Content for the first accordion" - , entryClass = defaultClass - , headerContent = Html.text "Default Look" + , content = \_ -> Html.text "🍎 There are many kinds of apples! Apples are more genetically diverse than humans. The genetic diversity of apples means that to preserve delicious apple varieties, growers must use grafting rather than seeds. In the apple market, clones have already taken over! 🍏" + , entryClass = entryClass + , headerContent = Html.text "Apples" , headerId = "accordion-entry__1" , headerLevel = Accordion.H4 , isExpanded = Set.member 1 model @@ -85,74 +85,85 @@ view model = } [ AccordionEntry { caret = defaultCaret - , content = \_ -> Html.text "Content for the Accordion Child" - , entryClass = defaultClass - , headerContent = Html.text "Accordion Child" - , headerId = "accordion-entry__2" + , content = + \_ -> + Html.div [] + [ Html.img "Basket of Gala Apples" + [ css [ Css.maxWidth (Css.px 100), Css.maxHeight (Css.px 100) ] + , src "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4b/Malus-Gala.jpg/1205px-Malus-Gala.jpg" + ] + , Html.a [ Attributes.href "https://en.wikipedia.org/wiki/Gala_(apple)" ] + [ Html.text "Wikipedia article on Gala Apples" ] + ] + , entryClass = entryClass + , headerContent = Html.text "Gala" + , headerId = "accordion-entry__11" , headerLevel = Accordion.H5 - , isExpanded = Set.member 2 model - , toggle = Just (Toggle 2) + , isExpanded = Set.member 11 model + , toggle = Just (Toggle 11) + } + [] + , AccordionEntry + { caret = defaultCaret + , content = + \_ -> + Html.div [] + [ Html.img "Freshly-washed Granny Smith Apple" + [ css [ Css.maxWidth (Css.px 100), Css.maxHeight (Css.px 100) ] + , src "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0e/One_Green_Apple.jpg/1280px-One_Green_Apple.jpg" + ] + , Html.a [ Attributes.href "https://en.wikipedia.org/wiki/Granny_Smith" ] + [ Html.text "Wikipedia article on Granny Smith Apples" ] + ] + , entryClass = entryClass + , headerContent = Html.text "Granny Smith" + , headerId = "accordion-entry__12" + , headerLevel = Accordion.H5 + , isExpanded = Set.member 12 model + , toggle = Just (Toggle 12) + } + [] + , AccordionEntry + { caret = defaultCaret + , content = + \_ -> + Html.div [] + [ Html.img "3 Fuji Apples resting on gingham fabric" + [ css [ Css.maxWidth (Css.px 100), Css.maxHeight (Css.px 100) ] + , src "https://upload.wikimedia.org/wikipedia/commons/thumb/8/81/Fuji_apples.jpg/1920px-Fuji_apples.jpg" + ] + , Html.a [ Attributes.href "https://en.wikipedia.org/wiki/Fuji_(apple)" ] + [ Html.text "Wikipedia article on Fuji Apples" ] + ] + , entryClass = entryClass + , headerContent = Html.text "Fuji" + , headerId = "accordion-entry__13" + , headerLevel = Accordion.H5 + , isExpanded = Set.member 13 model + , toggle = Just (Toggle 13) } [] ] , AccordionEntry - { caret = - \isOpen -> - UiIcon.seeMore - |> Svg.withWidth (Css.px 17) - |> Svg.withHeight (Css.px 17) - |> Svg.withCss [ Css.marginRight (Css.px 8) ] - |> Svg.withColor - (if isOpen then - Colors.azureDark - - else - Colors.azure - ) - |> Svg.toHtml - , content = \_ -> Html.text "Content for the third accordion" - , entryClass = defaultClass - , headerContent = Html.text "Custom Carets!" - , headerId = "accordion-entry__3" + { caret = defaultCaret + , content = \_ -> Html.text "🍊 I don't know anything about oranges! Except: YUM! 🍊" + , entryClass = entryClass + , headerContent = Html.text "Oranges" + , headerId = "accordion-entry__2" , headerLevel = Accordion.H4 - , isExpanded = Set.member 3 model - , toggle = Just (Toggle 3) + , isExpanded = Set.member 2 model + , toggle = Just (Toggle 2) } [] , AccordionEntry - { caret = - \_ -> - UiIcon.null - |> Svg.withWidth (Css.px 17) - |> Svg.withHeight (Css.px 17) - |> Svg.withCss [ Css.marginRight (Css.px 8) ] - |> Svg.withColor Colors.gray85 - |> Svg.toHtml - , content = \_ -> Html.text "Content for the fourth accordion" - , entryClass = defaultClass - , headerContent = Html.text "This accordion can't be opened." + { caret = defaultCaret + , content = \_ -> Html.text "There are many types of berries and all of them are delicious (or poisonous (or both)). Blackberries and mulberries are especially drool-worthy." + , entryClass = entryClass + , headerContent = Html.text "Berries" , headerId = "accordion-entry__4" , headerLevel = Accordion.H5 , isExpanded = Set.member 4 model - , toggle = Nothing - } - [] - , AccordionEntry - { caret = - \_ -> - UiIcon.null - |> Svg.withWidth (Css.px 17) - |> Svg.withHeight (Css.px 17) - |> Svg.withCss [ Css.marginRight (Css.px 8) ] - |> Svg.withColor Colors.gray85 - |> Svg.toHtml - , content = \_ -> Html.text "Content for the fifth accordion" - , entryClass = defaultClass - , headerContent = Html.text "This accordion can't be closed." - , headerId = "accordion-entry__5" - , headerLevel = Accordion.H5 - , isExpanded = True - , toggle = Nothing + , toggle = Just (Toggle 4) } [] , AccordionEntry From 515a4008792ec53679e84c2c2c211acf0a528b4c Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Wed, 5 May 2021 16:30:03 -0700 Subject: [PATCH 3/4] left-align the fixed position example --- styleguide-app/Examples/Accordion.elm | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/styleguide-app/Examples/Accordion.elm b/styleguide-app/Examples/Accordion.elm index 4aa37583..adcd6a6c 100644 --- a/styleguide-app/Examples/Accordion.elm +++ b/styleguide-app/Examples/Accordion.elm @@ -66,9 +66,6 @@ view model = let defaultCaret = DisclosureIndicator.large [ Css.marginRight (Css.px 8) ] - - entryClass = - "first-accordion-example" in [ Heading.h3 [] [ Html.text "Accordion.view" ] , Accordion.view @@ -76,7 +73,7 @@ view model = [ AccordionEntry { caret = defaultCaret , content = \_ -> Html.text "🍎 There are many kinds of apples! Apples are more genetically diverse than humans. The genetic diversity of apples means that to preserve delicious apple varieties, growers must use grafting rather than seeds. In the apple market, clones have already taken over! 🍏" - , entryClass = entryClass + , entryClass = "accordion-example" , headerContent = Html.text "Apples" , headerId = "accordion-entry__1" , headerLevel = Accordion.H4 @@ -95,7 +92,7 @@ view model = , Html.a [ Attributes.href "https://en.wikipedia.org/wiki/Gala_(apple)" ] [ Html.text "Wikipedia article on Gala Apples" ] ] - , entryClass = entryClass + , entryClass = "accordion-example-child" , headerContent = Html.text "Gala" , headerId = "accordion-entry__11" , headerLevel = Accordion.H5 @@ -115,7 +112,7 @@ view model = , Html.a [ Attributes.href "https://en.wikipedia.org/wiki/Granny_Smith" ] [ Html.text "Wikipedia article on Granny Smith Apples" ] ] - , entryClass = entryClass + , entryClass = "accordion-example-child" , headerContent = Html.text "Granny Smith" , headerId = "accordion-entry__12" , headerLevel = Accordion.H5 @@ -135,7 +132,7 @@ view model = , Html.a [ Attributes.href "https://en.wikipedia.org/wiki/Fuji_(apple)" ] [ Html.text "Wikipedia article on Fuji Apples" ] ] - , entryClass = entryClass + , entryClass = "accordion-example-child" , headerContent = Html.text "Fuji" , headerId = "accordion-entry__13" , headerLevel = Accordion.H5 @@ -147,7 +144,7 @@ view model = , AccordionEntry { caret = defaultCaret , content = \_ -> Html.text "🍊 I don't know anything about oranges! Except: YUM! 🍊" - , entryClass = entryClass + , entryClass = "accordion-example" , headerContent = Html.text "Oranges" , headerId = "accordion-entry__2" , headerLevel = Accordion.H4 @@ -158,7 +155,7 @@ view model = , AccordionEntry { caret = defaultCaret , content = \_ -> Html.text "There are many types of berries and all of them are delicious (or poisonous (or both)). Blackberries and mulberries are especially drool-worthy." - , entryClass = entryClass + , entryClass = "accordion-example" , headerContent = Html.text "Berries" , headerId = "accordion-entry__4" , headerLevel = Accordion.H5 @@ -177,7 +174,8 @@ view model = , Css.padding (Css.px 20) ] ] - [ Html.text "Content for the accordion" + [ Html.a [ Attributes.href "https://en.wikipedia.org/wiki/Apple#/media/File:95apple.jpeg" ] + [ Html.img "Wild Apple" [ src "https://upload.wikimedia.org/wikipedia/commons/9/92/95apple.jpeg" ] ] ] , entryClass = "fixed-positioning-accordion-example" , headerContent = Html.text "Fixed Position Example: Expand & Scroll!" @@ -192,10 +190,12 @@ view model = } , Accordion.styleAccordion { entryStyles = - [ Css.marginLeft (Css.px 16) - , Css.Global.withClass "fixed-positioning-accordion-example" - [ Css.position Css.relative + [ Css.Global.withClass "fixed-positioning-accordion-example" + [ Css.marginLeft (Css.px -20) + , Css.position Css.relative ] + , Css.Global.withClass "accordion-example-child" + [ Css.marginLeft (Css.px 16) ] ] , entryExpandedStyles = [ Css.Global.withClass "fixed-positioning-accordion-example" From f091193be6fe8e9db65deee94fa31adc6820ed01 Mon Sep 17 00:00:00 2001 From: Tessa Kelly Date: Wed, 5 May 2021 16:38:12 -0700 Subject: [PATCH 4/4] Use a custom icon for the advanced example --- styleguide-app/Examples/Accordion.elm | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/styleguide-app/Examples/Accordion.elm b/styleguide-app/Examples/Accordion.elm index adcd6a6c..b5b54d5e 100644 --- a/styleguide-app/Examples/Accordion.elm +++ b/styleguide-app/Examples/Accordion.elm @@ -164,7 +164,17 @@ view model = } [] , AccordionEntry - { caret = defaultCaret + { caret = + \isOpen -> + (if isOpen then + UiIcon.tree + + else + UiIcon.sprout + ) + |> Svg.withWidth (Css.px 30) + |> Svg.withCss [ Css.marginRight (Css.px 8) ] + |> Svg.toHtml , content = \_ -> Html.div @@ -178,7 +188,7 @@ view model = [ Html.img "Wild Apple" [ src "https://upload.wikimedia.org/wikipedia/commons/9/92/95apple.jpeg" ] ] ] , entryClass = "fixed-positioning-accordion-example" - , headerContent = Html.text "Fixed Position Example: Expand & Scroll!" + , headerContent = Html.text "Advanced Example: Expand & Scroll!" , headerId = "accordion-entry__6" , headerLevel = Accordion.H4 , isExpanded = Set.member 6 model