From 597604510cca61b0f078b4ac92da1eb96ff15486 Mon Sep 17 00:00:00 2001 From: James Robb <47126579+jamesrweb@users.noreply.github.com> Date: Sun, 11 Sep 2022 02:23:39 +0200 Subject: [PATCH 1/9] Require id and controls when setting up tabs and tabpanels --- src/Accessibility.elm | 78 +++++++++++++++++++++++++++++++++---- src/Accessibility/Utils.elm | 7 +++- 2 files changed, 76 insertions(+), 9 deletions(-) diff --git a/src/Accessibility.elm b/src/Accessibility.elm index c0cfa35..fb701f7 100644 --- a/src/Accessibility.elm +++ b/src/Accessibility.elm @@ -151,9 +151,13 @@ import Accessibility.Aria as Aria import Accessibility.Key as Key import Accessibility.Role as Role import Accessibility.Style as Style -import Accessibility.Utils exposing (nonInteractive) +import Accessibility.Utils exposing (Role(..), flip, nonInteractive) import Html as Html -import Html.Attributes +import Html.Attributes exposing (id, selected, tabindex) + + +type alias TabSettings = + { id : String, controls : List String, selected : Bool } {-| All inputs must be associated with a `label`. @@ -292,17 +296,75 @@ 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. + tab { id = "tab-1", controls = [ "element-1" ], selected = True } [] [ Html.p [] [ Html.text "Hello 1" ] ] + -} -tab : List (Attribute msg) -> List (Html msg) -> Html msg -tab attributes = - Html.div (Role.tab :: Key.tabbable True :: attributes) +tab : TabSettings -> List (Html.Attribute msg) -> List (Html msg) -> Html msg +tab settings attributes = + Html.div + (Role.tab + :: Key.tabbable True + :: id settings.id + :: Aria.controls settings.controls + :: selected settings.selected + :: Aria.selected settings.selected + :: attributes + ) {-| Create a tab panel. + + tabpanel [] + [ ( { id = "tab-1", controls = [ "element-1" ], selected = True }, Html.p [] [ Html.text "Hello 1" ] ) + , ( { id = "tab-2", controls = [ "element-2" ], selected = False }, Html.p [] [ Html.text "Hello 2" ] ) + ] + -} -tabPanel : List (Attribute Never) -> List (Html msg) -> Html msg -tabPanel attributes = - Html.div (Role.tabPanel :: nonInteractive attributes) +tabPanel : List (Attribute Never) -> List ( TabSettings, Html msg ) -> Html msg +tabPanel attributes childrenWithSettings = + let + {- + Only 0 or 1 children of a tab panel can ever be selected at any time. + -} + validChildren : Bool + validChildren = + List.map Tuple.first childrenWithSettings + |> List.filter .selected + |> List.length + |> flip List.member [ 0, 1 ] + + toTab : ( TabSettings, Html msg ) -> Html msg + toTab ( settings, el ) = + tab settings + [ tabindex + (if settings.selected then + 0 + + else + -1 + ) + , Aria.hidden (not settings.selected) + ] + [ el ] + + correctChildrenSelectionStates : ( TabSettings, Html msg ) -> ( List ( TabSettings, Html msg ), Bool ) -> ( List ( TabSettings, Html msg ), Bool ) + correctChildrenSelectionStates ( settings, element ) ( elements, hasSelectedEl ) = + if not hasSelectedEl && settings.selected then + ( List.append elements [ ( settings, element ) ], True ) + + else + ( List.append elements [ ( { settings | selected = False }, element ) ], hasSelectedEl ) + in + if validChildren then + Html.div + (Role.tabPanel :: nonInteractive attributes) + (List.map toTab childrenWithSettings) + + else + -- In the case that multiple tabs are selected, only allow the first one to actually be and reset the others to have a selected state of False. + Html.div + (Role.tabPanel :: nonInteractive attributes) + (childrenWithSettings |> List.foldl correctChildrenSelectionStates ( [], False ) |> Tuple.first |> List.map toTab) diff --git a/src/Accessibility/Utils.elm b/src/Accessibility/Utils.elm index 9985746..6dacbf7 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, flip, nonInteractive, role, roleToString, toBoolString, toListString, toTriStateString) import Html import Html.Attributes exposing (..) @@ -314,3 +314,8 @@ roleToString role_ = Treeitem -> "treeitem" + + +flip : (a -> b -> c) -> b -> a -> c +flip f a b = + f b a From 24459dd5ae2ee4fdfc2db103bce15bcbb72fac74 Mon Sep 17 00:00:00 2001 From: James Robb <47126579+jamesrweb@users.noreply.github.com> Date: Thu, 15 Sep 2022 22:48:46 +0200 Subject: [PATCH 2/9] Update implementation based on feedback --- src/Accessibility.elm | 87 +++++++++++++++++-------------------- src/Accessibility/Utils.elm | 4 +- 2 files changed, 42 insertions(+), 49 deletions(-) diff --git a/src/Accessibility.elm b/src/Accessibility.elm index fb701f7..b91a2ec 100644 --- a/src/Accessibility.elm +++ b/src/Accessibility.elm @@ -156,10 +156,6 @@ import Html as Html import Html.Attributes exposing (id, selected, tabindex) -type alias TabSettings = - { id : String, controls : List String, selected : Bool } - - {-| All inputs must be associated with a `label`. labelBefore [] viewLabel viewInput @@ -286,45 +282,11 @@ checkbox value_ maybeChecked attributes = {-| Create a tablist. This is the outer container for a list of tabs. -} -tabList : List (Attribute Never) -> List (Html msg) -> Html msg -tabList attributes = - Html.div (Role.tabList :: nonInteractive attributes) - - -{-| Create a tab. This is the part that you select in order to change panel views. - -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. - - tab { id = "tab-1", controls = [ "element-1" ], selected = True } [] [ Html.p [] [ Html.text "Hello 1" ] ] - --} -tab : TabSettings -> List (Html.Attribute msg) -> List (Html msg) -> Html msg -tab settings attributes = - Html.div - (Role.tab - :: Key.tabbable True - :: id settings.id - :: Aria.controls settings.controls - :: selected settings.selected - :: Aria.selected settings.selected - :: attributes - ) - - -{-| Create a tab panel. - - tabpanel [] - [ ( { id = "tab-1", controls = [ "element-1" ], selected = True }, Html.p [] [ Html.text "Hello 1" ] ) - , ( { id = "tab-2", controls = [ "element-2" ], selected = False }, Html.p [] [ Html.text "Hello 2" ] ) - ] - --} -tabPanel : List (Attribute Never) -> List ( TabSettings, Html msg ) -> Html msg -tabPanel attributes childrenWithSettings = +tabList : List (Attribute Never) -> List ( { id : String, controls : List String, selected : Bool }, Html msg ) -> Html msg +tabList attributes childrenWithSettings = let {- - Only 0 or 1 children of a tab panel can ever be selected at any time. + Only 0 or 1 children of a tabs can ever be selected at any time. -} validChildren : Bool validChildren = @@ -333,7 +295,7 @@ tabPanel attributes childrenWithSettings = |> List.length |> flip List.member [ 0, 1 ] - toTab : ( TabSettings, Html msg ) -> Html msg + toTab : ( { id : String, controls : List String, selected : Bool }, Html msg ) -> Html msg toTab ( settings, el ) = tab settings [ tabindex @@ -347,7 +309,7 @@ tabPanel attributes childrenWithSettings = ] [ el ] - correctChildrenSelectionStates : ( TabSettings, Html msg ) -> ( List ( TabSettings, Html msg ), Bool ) -> ( List ( TabSettings, Html msg ), Bool ) + correctChildrenSelectionStates : ( { id : String, controls : List String, selected : Bool }, Html msg ) -> ( List ( { id : String, controls : List String, selected : Bool }, Html msg ), Bool ) -> ( List ( { id : String, controls : List String, selected : Bool }, Html msg ), Bool ) correctChildrenSelectionStates ( settings, element ) ( elements, hasSelectedEl ) = if not hasSelectedEl && settings.selected then ( List.append elements [ ( settings, element ) ], True ) @@ -357,14 +319,45 @@ tabPanel attributes childrenWithSettings = in if validChildren then Html.div - (Role.tabPanel :: nonInteractive attributes) + (Role.tabList :: nonInteractive attributes) (List.map toTab childrenWithSettings) else - -- In the case that multiple tabs are selected, only allow the first one to actually be and reset the others to have a selected state of False. Html.div - (Role.tabPanel :: nonInteractive attributes) - (childrenWithSettings |> List.foldl correctChildrenSelectionStates ( [], False ) |> Tuple.first |> List.map toTab) + (Role.tabList :: nonInteractive attributes) + (childrenWithSettings + |> List.foldl correctChildrenSelectionStates ( [], False ) + |> Tuple.first + |> List.map toTab + ) + + +{-| Create a tab. This is the part that you select in order to change panel views. + +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. + + tab { id = "tab-1", controls = [ "element-1" ], selected = True } [] [ Html.p [] [ Html.text "Hello 1" ] ] + +-} +tab : { id : String, controls : List String, selected : Bool } -> List (Html.Attribute msg) -> List (Html msg) -> Html msg +tab settings attributes = + Html.div + (Role.tab + :: Key.tabbable True + :: id settings.id + :: Aria.controls settings.controls + :: selected settings.selected + :: 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) diff --git a/src/Accessibility/Utils.elm b/src/Accessibility/Utils.elm index 6dacbf7..f192782 100644 --- a/src/Accessibility/Utils.elm +++ b/src/Accessibility/Utils.elm @@ -317,5 +317,5 @@ roleToString role_ = flip : (a -> b -> c) -> b -> a -> c -flip f a b = - f b a +flip f b a = + f a b From 412ec7898b2aa55c9923f25ccb1a7e0a6f476f6c Mon Sep 17 00:00:00 2001 From: James Robb <47126579+jamesrweb@users.noreply.github.com> Date: Thu, 15 Sep 2022 23:57:24 +0200 Subject: [PATCH 3/9] Simplify implementation to only affect tabs --- src/Accessibility.elm | 68 ++++++++-------------------------- src/Accessibility/Aria.elm | 2 +- src/Accessibility/Key.elm | 2 +- src/Accessibility/Landmark.elm | 2 +- src/Accessibility/Live.elm | 2 +- src/Accessibility/Role.elm | 13 +------ src/Accessibility/Style.elm | 2 +- src/Accessibility/Utils.elm | 7 +--- 8 files changed, 22 insertions(+), 76 deletions(-) diff --git a/src/Accessibility.elm b/src/Accessibility.elm index b91a2ec..833560d 100644 --- a/src/Accessibility.elm +++ b/src/Accessibility.elm @@ -151,8 +151,8 @@ import Accessibility.Aria as Aria import Accessibility.Key as Key import Accessibility.Role as Role import Accessibility.Style as Style -import Accessibility.Utils exposing (Role(..), flip, nonInteractive) -import Html as Html +import Accessibility.Utils exposing (nonInteractive) +import Html import Html.Attributes exposing (id, selected, tabindex) @@ -282,54 +282,9 @@ checkbox value_ maybeChecked attributes = {-| Create a tablist. This is the outer container for a list of tabs. -} -tabList : List (Attribute Never) -> List ( { id : String, controls : List String, selected : Bool }, Html msg ) -> Html msg -tabList attributes childrenWithSettings = - let - {- - Only 0 or 1 children of a tabs can ever be selected at any time. - -} - validChildren : Bool - validChildren = - List.map Tuple.first childrenWithSettings - |> List.filter .selected - |> List.length - |> flip List.member [ 0, 1 ] - - toTab : ( { id : String, controls : List String, selected : Bool }, Html msg ) -> Html msg - toTab ( settings, el ) = - tab settings - [ tabindex - (if settings.selected then - 0 - - else - -1 - ) - , Aria.hidden (not settings.selected) - ] - [ el ] - - correctChildrenSelectionStates : ( { id : String, controls : List String, selected : Bool }, Html msg ) -> ( List ( { id : String, controls : List String, selected : Bool }, Html msg ), Bool ) -> ( List ( { id : String, controls : List String, selected : Bool }, Html msg ), Bool ) - correctChildrenSelectionStates ( settings, element ) ( elements, hasSelectedEl ) = - if not hasSelectedEl && settings.selected then - ( List.append elements [ ( settings, element ) ], True ) - - else - ( List.append elements [ ( { settings | selected = False }, element ) ], hasSelectedEl ) - in - if validChildren then - Html.div - (Role.tabList :: nonInteractive attributes) - (List.map toTab childrenWithSettings) - - else - Html.div - (Role.tabList :: nonInteractive attributes) - (childrenWithSettings - |> List.foldl correctChildrenSelectionStates ( [], False ) - |> Tuple.first - |> List.map toTab - ) +tabList : List (Attribute Never) -> List (Html msg) -> Html msg +tabList attributes = + Html.div (Role.tabList :: nonInteractive attributes) {-| Create a tab. This is the part that you select in order to change panel views. @@ -337,18 +292,25 @@ tabList attributes childrenWithSettings = 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. - tab { id = "tab-1", controls = [ "element-1" ], selected = True } [] [ Html.p [] [ Html.text "Hello 1" ] ] + tab { id = "tab-1", controls = "tab-panel-1", selected = True } [] [ Html.text "Tab 1" ] -} -tab : { id : String, controls : List String, selected : Bool } -> List (Html.Attribute msg) -> List (Html msg) -> Html msg +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 True :: id settings.id - :: Aria.controls settings.controls + :: Aria.controls [ settings.controls ] :: selected settings.selected :: Aria.selected settings.selected + :: tabindex + (if settings.selected then + 0 + + else + -1 + ) :: attributes ) 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 f192782..510cca5 100644 --- a/src/Accessibility/Utils.elm +++ b/src/Accessibility/Utils.elm @@ -1,4 +1,4 @@ -module Accessibility.Utils exposing (Role(..), aria, flip, nonInteractive, role, roleToString, toBoolString, toListString, toTriStateString) +module Accessibility.Utils exposing (Role(..), aria, nonInteractive, role, toBoolString, toListString, toTriStateString) import Html import Html.Attributes exposing (..) @@ -314,8 +314,3 @@ roleToString role_ = Treeitem -> "treeitem" - - -flip : (a -> b -> c) -> b -> a -> c -flip f b a = - f a b From 15156a6bf77226da6ae2c64d44e9d8bd39d0010e Mon Sep 17 00:00:00 2001 From: James Robb <47126579+jamesrweb@users.noreply.github.com> Date: Wed, 21 Sep 2022 11:01:59 +0200 Subject: [PATCH 4/9] Remove selected attribute from tab --- src/Accessibility.elm | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Accessibility.elm b/src/Accessibility.elm index 833560d..3edeb44 100644 --- a/src/Accessibility.elm +++ b/src/Accessibility.elm @@ -302,7 +302,6 @@ tab settings attributes = :: Key.tabbable True :: id settings.id :: Aria.controls [ settings.controls ] - :: selected settings.selected :: Aria.selected settings.selected :: tabindex (if settings.selected then From 1884ef919a440c032b52481c0d36a32523b41c11 Mon Sep 17 00:00:00 2001 From: James Robb <47126579+jamesrweb@users.noreply.github.com> Date: Wed, 21 Sep 2022 11:02:58 +0200 Subject: [PATCH 5/9] Remove duplicate tabindex --- src/Accessibility.elm | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Accessibility.elm b/src/Accessibility.elm index 3edeb44..804844b 100644 --- a/src/Accessibility.elm +++ b/src/Accessibility.elm @@ -299,17 +299,10 @@ tab : { id : String, controls : String, selected : Bool } -> List (Html.Attribut tab settings attributes = Html.div (Role.tab - :: Key.tabbable True + :: Key.tabbable settings.selected :: id settings.id :: Aria.controls [ settings.controls ] :: Aria.selected settings.selected - :: tabindex - (if settings.selected then - 0 - - else - -1 - ) :: attributes ) From 32974b820a7c0978bef68493140d78e5a3ea9a85 Mon Sep 17 00:00:00 2001 From: James Robb <47126579+jamesrweb@users.noreply.github.com> Date: Wed, 21 Sep 2022 11:04:00 +0200 Subject: [PATCH 6/9] Add controls comment --- src/Accessibility.elm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Accessibility.elm b/src/Accessibility.elm index 804844b..f835808 100644 --- a/src/Accessibility.elm +++ b/src/Accessibility.elm @@ -292,6 +292,8 @@ 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" ] -} From c1e1acb225039676eaa075535dfcb27517127b93 Mon Sep 17 00:00:00 2001 From: James Robb <47126579+jamesrweb@users.noreply.github.com> Date: Thu, 6 Oct 2022 11:18:24 +0200 Subject: [PATCH 7/9] Add and expose a new viewTabs helper function --- src/Accessibility.elm | 51 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/src/Accessibility.elm b/src/Accessibility.elm index f835808..9c9f6e6 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 , 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 ## Images @@ -153,7 +153,7 @@ import Accessibility.Role as Role import Accessibility.Style as Style import Accessibility.Utils exposing (nonInteractive) import Html -import Html.Attributes exposing (id, selected, tabindex) +import Html.Attributes exposing (id) {-| All inputs must be associated with a `label`. @@ -311,9 +311,48 @@ tab settings 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 :: Role.tabPanel :: nonInteractive attributes) + + +type alias Tab msg = + { tabId : String + , panelId : String + , tabContent : List (Html msg) + , panelContent : List (Html msg) + } + + +{-| Create a set of tabs with associated panels. + + viewTabs + [ { 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" ] } + ] + "tab-1" + +-} +viewTabs : List (Tab msg) -> String -> Html msg +viewTabs tabs selectedTabId = + let + toTab : Tab msg -> Html msg + toTab { tabId, panelId, tabContent } = + tab + { id = tabId, controls = panelId, selected = selectedTabId == tabId } + [] + tabContent + + toTabPanel : Tab msg -> Html msg + toTabPanel { panelId, panelContent } = + tabPanel + { id = panelId } + [] + panelContent + in + [ List.map toTab tabs, List.map toTabPanel tabs ] + |> List.concat + |> Html.div [] From 27f76d6cb57032923eb83d2988cfedd6222e637a Mon Sep 17 00:00:00 2001 From: James Robb <47126579+jamesrweb@users.noreply.github.com> Date: Tue, 11 Oct 2022 17:08:24 +0200 Subject: [PATCH 8/9] Update viewTabs type signature and apply requested changes --- src/Accessibility.elm | 51 +++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/src/Accessibility.elm b/src/Accessibility.elm index 9c9f6e6..10a457c 100644 --- a/src/Accessibility.elm +++ b/src/Accessibility.elm @@ -22,6 +22,7 @@ module Accessibility exposing , mark, ruby, rt, rp, bdi, bdo, wbr , details, summary, menuitem, menu , Html, Attribute, map + , ViewTabsSettings ) {-| @@ -313,33 +314,43 @@ tab settings attributes = -} tabPanel : { id : String } -> List (Attribute Never) -> List (Html msg) -> Html msg tabPanel settings attributes = - Html.div (id settings.id :: Role.tabPanel :: nonInteractive attributes) + Html.div (id settings.id :: Aria.labelledBy settings.id :: Role.tabPanel :: nonInteractive attributes) -type alias Tab 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 + { tabId : String + , panelId : String + , tabContent : List (Html msg) + , panelContent : List (Html msg) + } + , selectedTabId : String + , tabListAttributes : List (Attribute Never) } {-| Create a set of tabs with associated panels. viewTabs - [ { 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" ] } - ] - "tab-1" + { 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 : List (Tab msg) -> String -> Html msg -viewTabs tabs selectedTabId = +viewTabs : ViewTabsSettings msg -> Html msg +viewTabs settings = let toTab : Tab msg -> Html msg toTab { tabId, panelId, tabContent } = tab - { id = tabId, controls = panelId, selected = selectedTabId == tabId } + { id = tabId, controls = panelId, selected = settings.selectedTabId == tabId } [] tabContent @@ -349,8 +360,20 @@ viewTabs tabs selectedTabId = { 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.map toTab tabs, List.map toTabPanel tabs ] + [ List.singleton tabListForTabs, tabPanels ] |> List.concat |> Html.div [] From 2ac5d917f80565e9570dbcaf8b898aac475e0ffe Mon Sep 17 00:00:00 2001 From: James Robb <47126579+jamesrweb@users.noreply.github.com> Date: Tue, 11 Oct 2022 17:14:08 +0200 Subject: [PATCH 9/9] Fix type issue --- src/Accessibility.elm | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/Accessibility.elm b/src/Accessibility.elm index 10a457c..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, viewTabs + , tabList, tab, tabPanel, viewTabs, TabConfig, ViewTabsSettings , img, decorativeImg , button, textarea, select , text @@ -22,7 +22,6 @@ module Accessibility exposing , mark, ruby, rt, rp, bdi, bdo, wbr , details, summary, menuitem, menu , Html, Attribute, map - , ViewTabsSettings ) {-| @@ -82,7 +81,7 @@ Together, `tabList`, `tab`, and `tabPanel` describe the pieces of a tab componen [ text "Panel Two Content" ] ] -@docs tabList, tab, tabPanel, viewTabs +@docs tabList, tab, tabPanel, viewTabs, TabConfig, ViewTabsSettings ## Images @@ -317,16 +316,20 @@ 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 - { tabId : String - , panelId : String - , tabContent : List (Html msg) - , panelContent : List (Html msg) - } + { tabs : List (TabConfig msg) , selectedTabId : String , tabListAttributes : List (Attribute Never) } @@ -347,14 +350,14 @@ type alias ViewTabsSettings msg = viewTabs : ViewTabsSettings msg -> Html msg viewTabs settings = let - toTab : Tab msg -> Html msg + toTab : TabConfig msg -> Html msg toTab { tabId, panelId, tabContent } = tab { id = tabId, controls = panelId, selected = settings.selectedTabId == tabId } [] tabContent - toTabPanel : Tab msg -> Html msg + toTabPanel : TabConfig msg -> Html msg toTabPanel { panelId, panelContent } = tabPanel { id = panelId }