From b3aeaff5d26dd76ba86a9070459bd977036fa6fd Mon Sep 17 00:00:00 2001 From: Steven Bone Date: Fri, 26 Sep 2025 09:34:55 -0500 Subject: [PATCH 1/2] Don't render headers when all children selected --- src/GroupedDropdownOptions.elm | 75 ++++++++++++++++------------ tests/Option/OrderingInGroups.elm | 81 ++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 33 deletions(-) diff --git a/src/GroupedDropdownOptions.elm b/src/GroupedDropdownOptions.elm index 46780b3e..1c6db6f0 100644 --- a/src/GroupedDropdownOptions.elm +++ b/src/GroupedDropdownOptions.elm @@ -63,39 +63,50 @@ optionGroupsToHtml dropdownItemEventListeners selectionConfig groupedDropdownOpt optionGroupToHtml : DropdownItemEventListeners msg -> SelectionConfig -> DropdownOptionsGroup -> List (Html msg) optionGroupToHtml dropdownItemEventListeners selectionMode dropdownOptionsGroup = let - optionGroupHtml = - case dropdownOptionsGroup |> getOptions |> DropdownOptions.maybeFirstOptionSearchFilter of - Just optionSearchFilter -> - case dropdownOptionsGroup |> getOptionsGroup |> OptionGroup.toString of - "" -> - text "" - - _ -> - div - [ class "optgroup" - , Html.Attributes.attribute "part" "dropdown-optgroup" - ] - [ span [ class "optgroup-header" ] - (tokensToHtml optionSearchFilter.groupTokens) - ] - - Nothing -> - case dropdownOptionsGroup |> getOptionsGroup |> OptionGroup.toString of - "" -> - text "" - - optionGroupAsString -> - div - [ class "optgroup" - , Html.Attributes.attribute "part" "dropdown-optgroup" - ] - [ span [ class "optgroup-header" ] - [ text - optionGroupAsString - ] - ] + options = + getOptions dropdownOptionsGroup + + optionsHtml = + optionsToCustomHtml dropdownItemEventListeners selectionMode options in - optionGroupHtml :: optionsToCustomHtml dropdownItemEventListeners selectionMode (getOptions dropdownOptionsGroup) + if DropdownOptions.isEmpty options then + [] + + else + let + optionGroupHtml = + case options |> DropdownOptions.maybeFirstOptionSearchFilter of + Just optionSearchFilter -> + case dropdownOptionsGroup |> getOptionsGroup |> OptionGroup.toString of + "" -> + text "" + + _ -> + div + [ class "optgroup" + , Html.Attributes.attribute "part" "dropdown-optgroup" + ] + [ span [ class "optgroup-header" ] + (tokensToHtml optionSearchFilter.groupTokens) + ] + + Nothing -> + case dropdownOptionsGroup |> getOptionsGroup |> OptionGroup.toString of + "" -> + text "" + + optionGroupAsString -> + div + [ class "optgroup" + , Html.Attributes.attribute "part" "dropdown-optgroup" + ] + [ span [ class "optgroup-header" ] + [ text + optionGroupAsString + ] + ] + in + optionGroupHtml :: optionsHtml dropdownOptionsToDatalistHtml : DropdownOptions -> Html msg diff --git a/tests/Option/OrderingInGroups.elm b/tests/Option/OrderingInGroups.elm index 721f7871..0b33b586 100644 --- a/tests/Option/OrderingInGroups.elm +++ b/tests/Option/OrderingInGroups.elm @@ -1,11 +1,15 @@ module Option.OrderingInGroups exposing (suite) +import DropdownItemEventListeners exposing (DropdownItemEventListeners) import DropdownOptions import Expect import GroupedDropdownOptions -import Option exposing (Option(..), setGroupWithString, test_newFancyOptionWithMaybeCleanString) +import Html exposing (Html) +import Option exposing (Option(..), newSelectedOption, setGroupWithString, test_newFancyOptionWithMaybeCleanString) import OptionGroup exposing (OptionGroup) import OptionList +import OptionValue +import SelectionMode exposing (defaultSelectionConfig) import Test exposing (Test, describe, test) @@ -67,6 +71,31 @@ optionGroupToDebuggingString optionGroup = OptionGroup.toString optionGroup + +-- Mock event listeners for testing HTML rendering + + +mockEventListeners : DropdownItemEventListeners String +mockEventListeners = + { mouseOverMsgConstructor = \_ -> "mouseOver" + , mouseOutMsgConstructor = \_ -> "mouseOut" + , mouseDownMsgConstructor = \_ -> "mouseDown" + , mouseUpMsgConstructor = \_ -> "mouseUp" + , noOpMsgConstructor = "noOp" + } + + + +-- Helper function to count optgroup headers by checking rendered HTML length +-- Since optgroups with no options return empty lists, we can test by checking +-- if the groups were filtered out properly + + +countNonEmptyGroups : List (Html msg) -> Int +countNonEmptyGroups htmlList = + List.length htmlList + + suite : Test suite = describe "When we have a sorted list of options" @@ -90,4 +119,54 @@ suite = ) ) ) + , test "hide optgroup headers when all options in the group are selected" <| + \_ -> + let + -- Create options where all Hand Tools are selected + selectedScrewDriver = + newSelectedOption 0 "Screw Driver" Nothing |> setGroupWithString "Hand Tool" + + selectedWrench = + newSelectedOption 1 "Wrench" Nothing |> setGroupWithString "Hand Tool" + + selectedHammer = + newSelectedOption 2 "Hammer" Nothing |> setGroupWithString "Hand Tool" + + selectedChisel = + newSelectedOption 3 "Chisel" Nothing |> setGroupWithString "Hand Tool" + + -- Power Tools remain unselected + unselectedDrill = + drill + + unselectedSawZaw = + sawZaw + + allOptions = + OptionList.FancyOptionList + [ selectedScrewDriver + , unselectedDrill + , selectedWrench + , unselectedSawZaw + , selectedHammer + , selectedChisel + ] + + -- Get only unselected options (what would show in dropdown) + unselectedOnlyOptions = + DropdownOptions.figureOutWhichOptionsToShowInTheDropdownThatAreNotSelected + defaultSelectionConfig + allOptions + + -- Render the HTML + renderedHtml = + GroupedDropdownOptions.groupOptionsInOrder unselectedOnlyOptions + |> GroupedDropdownOptions.optionGroupsToHtml mockEventListeners defaultSelectionConfig + + -- Count HTML elements - should only have Power Tool options, Hand Tool group should be filtered out + elementCount = + countNonEmptyGroups renderedHtml + in + -- Should only have elements from Power Tool group (header + 2 options = 3), Hand Tool group should be filtered out completely + Expect.equal 3 elementCount ] From 1078a1095e5ad0e32ba143a310411a6d3e53449c Mon Sep 17 00:00:00 2001 From: Steven Bone Date: Fri, 26 Sep 2025 09:38:38 -0500 Subject: [PATCH 2/2] Tidy up tests --- tests/Option/OrderingInGroups.elm | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/tests/Option/OrderingInGroups.elm b/tests/Option/OrderingInGroups.elm index 0b33b586..970877e3 100644 --- a/tests/Option/OrderingInGroups.elm +++ b/tests/Option/OrderingInGroups.elm @@ -85,17 +85,6 @@ mockEventListeners = } - --- Helper function to count optgroup headers by checking rendered HTML length --- Since optgroups with no options return empty lists, we can test by checking --- if the groups were filtered out properly - - -countNonEmptyGroups : List (Html msg) -> Int -countNonEmptyGroups htmlList = - List.length htmlList - - suite : Test suite = describe "When we have a sorted list of options" @@ -122,7 +111,6 @@ suite = , test "hide optgroup headers when all options in the group are selected" <| \_ -> let - -- Create options where all Hand Tools are selected selectedScrewDriver = newSelectedOption 0 "Screw Driver" Nothing |> setGroupWithString "Hand Tool" @@ -135,7 +123,6 @@ suite = selectedChisel = newSelectedOption 3 "Chisel" Nothing |> setGroupWithString "Hand Tool" - -- Power Tools remain unselected unselectedDrill = drill @@ -152,21 +139,17 @@ suite = , selectedChisel ] - -- Get only unselected options (what would show in dropdown) unselectedOnlyOptions = DropdownOptions.figureOutWhichOptionsToShowInTheDropdownThatAreNotSelected defaultSelectionConfig allOptions - -- Render the HTML renderedHtml = GroupedDropdownOptions.groupOptionsInOrder unselectedOnlyOptions |> GroupedDropdownOptions.optionGroupsToHtml mockEventListeners defaultSelectionConfig - -- Count HTML elements - should only have Power Tool options, Hand Tool group should be filtered out elementCount = - countNonEmptyGroups renderedHtml + List.length renderedHtml in - -- Should only have elements from Power Tool group (header + 2 options = 3), Hand Tool group should be filtered out completely Expect.equal 3 elementCount ]