diff --git a/src/Accessibility.elm b/src/Accessibility.elm index c0cfa35..2bdba11 100644 --- a/src/Accessibility.elm +++ b/src/Accessibility.elm @@ -1,7 +1,7 @@ module Accessibility exposing ( labelBefore, labelAfter, labelHidden , inputText, inputNumber, radio, checkbox - , tabList, tab, tabPanel + , tabList, tab, tabPanel, viewTabs, TabConfig, ViewTabsSettings , img, decorativeImg , button, textarea, select , text @@ -81,7 +81,7 @@ Together, `tabList`, `tab`, and `tabPanel` describe the pieces of a tab componen [ text "Panel Two Content" ] ] -@docs tabList, tab, tabPanel +@docs tabList, tab, tabPanel, viewTabs, TabConfig, ViewTabsSettings ## Images @@ -152,8 +152,8 @@ import Accessibility.Key as Key import Accessibility.Role as Role import Accessibility.Style as Style import Accessibility.Utils exposing (nonInteractive) -import Html as Html -import Html.Attributes +import Html +import Html.Attributes exposing (id) {-| All inputs must be associated with a `label`. @@ -292,17 +292,93 @@ tabList attributes = You'll want to listen for click events **and** for keyboard events: when users hit the right and left keys on their keyboards, they expect for the selected tab to change. +The controls setting is the ID of the tabpanel related to the tab. These must be the same! + + tab { id = "tab-1", controls = "tab-panel-1", selected = True } [] [ Html.text "Tab 1" ] + -} -tab : List (Attribute msg) -> List (Html msg) -> Html msg -tab attributes = - Html.div (Role.tab :: Key.tabbable True :: attributes) +tab : { id : String, controls : String, selected : Bool } -> List (Html.Attribute msg) -> List (Html msg) -> Html msg +tab settings attributes = + Html.div + (Role.tab + :: Key.tabbable settings.selected + :: id settings.id + :: Aria.controls [ settings.controls ] + :: Aria.selected settings.selected + :: attributes + ) {-| Create a tab panel. -} -tabPanel : List (Attribute Never) -> List (Html msg) -> Html msg -tabPanel attributes = - Html.div (Role.tabPanel :: nonInteractive attributes) +tabPanel : { id : String } -> List (Attribute Never) -> List (Html msg) -> Html msg +tabPanel settings attributes = + Html.div (id settings.id :: Aria.labelledBy settings.id :: Role.tabPanel :: nonInteractive attributes) + + +{-| Representation type for a tab for use in the [viewTabs](#viewTabs) helper function. +-} +type alias TabConfig msg = + { tabId : String + , panelId : String + , tabContent : List (Html msg) + , panelContent : List (Html msg) + } + + +{-| Settings required for the [viewTabs](#viewTabs) helper function to generate the correct structure for a tab layout. +-} +type alias ViewTabsSettings msg = + { tabs : List (TabConfig msg) + , selectedTabId : String + , tabListAttributes : List (Attribute Never) + } + + +{-| Create a set of tabs with associated panels. + + viewTabs + { tabs = + [ { tabId = "tab-1", panelId = "panel-1", tabContent = Html.p [] [ Html.text "Tab content 1" ], panelContent = Html.p [] [ Html.text "Panel content 1" ] } + , { tabId = "tab-2", panelId = "panel-2", tabContent = Html.p [] [ Html.text "Tab content 2" ], panelContent = Html.p [] [ Html.text "Panel content 2" ] } + ] + , selectedTabId = "tab-1" + , tabListAttributes = [ Html.Attributes.class "tablist" ] + } + +-} +viewTabs : ViewTabsSettings msg -> Html msg +viewTabs settings = + let + toTab : TabConfig msg -> Html msg + toTab { tabId, panelId, tabContent } = + tab + { id = tabId, controls = panelId, selected = settings.selectedTabId == tabId } + [] + tabContent + + toTabPanel : TabConfig msg -> Html msg + toTabPanel { panelId, panelContent } = + tabPanel + { id = panelId } + [] + panelContent + + tabs : List (Html msg) + tabs = + List.map toTab settings.tabs + + tabPanels : List (Html msg) + tabPanels = + List.map toTabPanel settings.tabs + + tabListForTabs : Html msg + tabListForTabs = + tabList settings.tabListAttributes tabs + in + [ List.singleton tabListForTabs, tabPanels ] + |> List.concat + |> Html.div [] diff --git a/src/Accessibility/Aria.elm b/src/Accessibility/Aria.elm index c0cf7ea..ff38e06 100644 --- a/src/Accessibility/Aria.elm +++ b/src/Accessibility/Aria.elm @@ -136,7 +136,7 @@ See [the spec](https://www.w3.org/TR/wai-aria-1.1/#aria-haspopup). -} import Accessibility.Utils exposing (..) -import Html as Html +import Html import Html.Attributes exposing (..) import Json.Encode diff --git a/src/Accessibility/Key.elm b/src/Accessibility/Key.elm index 97762eb..9657017 100644 --- a/src/Accessibility/Key.elm +++ b/src/Accessibility/Key.elm @@ -41,7 +41,7 @@ module Accessibility.Key exposing -} -import Html as Html exposing (Attribute) +import Html exposing (Attribute) import Html.Attributes import Html.Events exposing (keyCode, on) import Json.Decode as Json diff --git a/src/Accessibility/Landmark.elm b/src/Accessibility/Landmark.elm index 725fcab..53ed924 100644 --- a/src/Accessibility/Landmark.elm +++ b/src/Accessibility/Landmark.elm @@ -15,7 +15,7 @@ The landmark you're most likely to need to set directly is `search`, as it does -} import Accessibility.Utils exposing (Role(..), role) -import Html as Html +import Html {-| Creates a [`role="banner"`](https://www.w3.org/TR/wai-aria-1.1/#banner) attribute. diff --git a/src/Accessibility/Live.elm b/src/Accessibility/Live.elm index 442b0bc..ade6c45 100644 --- a/src/Accessibility/Live.elm +++ b/src/Accessibility/Live.elm @@ -20,7 +20,7 @@ Learn more about how to use live regions [here](https://www.w3.org/TR/wai-aria-p -} import Accessibility.Utils exposing (..) -import Html as Html +import Html {-| Supported for all elements. diff --git a/src/Accessibility/Role.elm b/src/Accessibility/Role.elm index e39563c..ce2ca85 100644 --- a/src/Accessibility/Role.elm +++ b/src/Accessibility/Role.elm @@ -90,18 +90,7 @@ module Accessibility.Role exposing -} import Accessibility.Utils exposing (Role(..), role) -import Html as Html -import Html.Attributes - - -{-| Set the role of a given element to be a given string. - - div [ custom "tablist" ] [ tab1, tab2 ] - --} -custom : String -> Html.Attribute msg -custom = - Html.Attributes.attribute "role" +import Html {-| Add [`role="alert"`](https://www.w3.org/TR/wai-aria-1.1/#alert) to the attributes of an element. diff --git a/src/Accessibility/Style.elm b/src/Accessibility/Style.elm index 767b4bf..d73f5d8 100644 --- a/src/Accessibility/Style.elm +++ b/src/Accessibility/Style.elm @@ -16,7 +16,7 @@ For more information on hiding/semi-hiding elements, please see [the a11y projec -} -import Html as Html +import Html import Html.Attributes diff --git a/src/Accessibility/Utils.elm b/src/Accessibility/Utils.elm index 9985746..510cca5 100644 --- a/src/Accessibility/Utils.elm +++ b/src/Accessibility/Utils.elm @@ -1,4 +1,4 @@ -module Accessibility.Utils exposing (Role(..), aria, nonInteractive, role, roleToString, toBoolString, toListString, toTriStateString) +module Accessibility.Utils exposing (Role(..), aria, nonInteractive, role, toBoolString, toListString, toTriStateString) import Html import Html.Attributes exposing (..)