mirror of
https://github.com/nunntom/elm-ui-select.git
synced 2024-11-22 03:33:11 +03:00
FEATURE: Add withSelectOnTab
This commit is contained in:
parent
144527ed0c
commit
34f576fb3e
@ -21,7 +21,6 @@ import NoDebug.TodoOrToString
|
||||
import NoExposingEverything
|
||||
import NoImportingEverything
|
||||
import NoMissingTypeAnnotation
|
||||
import NoMissingTypeAnnotationInLetIn
|
||||
import NoPrematureLetComputation
|
||||
import NoSimpleLetBody
|
||||
import NoUnused.CustomTypeConstructorArgs
|
||||
@ -51,7 +50,6 @@ config =
|
||||
, NoExposingEverything.rule
|
||||
, NoImportingEverything.rule []
|
||||
, NoMissingTypeAnnotation.rule
|
||||
, NoMissingTypeAnnotationInLetIn.rule
|
||||
, NoSimpleLetBody.rule
|
||||
, NoPrematureLetComputation.rule
|
||||
, NoUnused.CustomTypeConstructors.rule []
|
||||
|
@ -56,7 +56,7 @@ type alias InternalState a =
|
||||
, items : List a
|
||||
, selected : Maybe a
|
||||
, inputValue : String
|
||||
, highlighted : Int
|
||||
, highlighted : Maybe Int
|
||||
, menuOpen : Bool
|
||||
, containerElement : Maybe Dom.Element
|
||||
, menuViewPort : Maybe Dom.Viewport
|
||||
@ -77,7 +77,7 @@ init id =
|
||||
, items = []
|
||||
, selected = Nothing
|
||||
, inputValue = ""
|
||||
, highlighted = 0
|
||||
, highlighted = Nothing
|
||||
, menuOpen = False
|
||||
, containerElement = Nothing
|
||||
, menuViewPort = Nothing
|
||||
@ -111,7 +111,7 @@ toRequestState (Model { requestState }) =
|
||||
requestState
|
||||
|
||||
|
||||
toHighlighted : Model a -> Int
|
||||
toHighlighted : Model a -> Maybe Int
|
||||
toHighlighted (Model { highlighted }) =
|
||||
highlighted
|
||||
|
||||
@ -149,10 +149,10 @@ toOptionElementId (Model { id }) idx =
|
||||
|
||||
toOptionState : Model a -> ( Int, a ) -> OptionState
|
||||
toOptionState (Model { highlighted, selected }) ( idx, a ) =
|
||||
if highlighted == idx && selected == Just a then
|
||||
if highlighted == Just idx && selected == Just a then
|
||||
SelectedAndHighlighted
|
||||
|
||||
else if highlighted == idx then
|
||||
else if highlighted == Just idx then
|
||||
Highlighted
|
||||
|
||||
else if selected == Just a then
|
||||
@ -240,7 +240,7 @@ selectOption opt (Model model) =
|
||||
}
|
||||
|
||||
|
||||
highlightIndex : Int -> Model a -> Model a
|
||||
highlightIndex : Maybe Int -> Model a -> Model a
|
||||
highlightIndex idx (Model model) =
|
||||
Model { model | highlighted = idx }
|
||||
|
||||
@ -260,7 +260,7 @@ closeMenu (Model model) =
|
||||
Model
|
||||
{ model
|
||||
| menuOpen = False
|
||||
, highlighted = 0
|
||||
, highlighted = Nothing
|
||||
}
|
||||
|
||||
|
||||
@ -270,7 +270,7 @@ clear (Model model) =
|
||||
{ model
|
||||
| inputValue = ""
|
||||
, selected = Nothing
|
||||
, highlighted = 0
|
||||
, highlighted = Nothing
|
||||
, applyFilter = False
|
||||
, menuOpen = False
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ type Msg a
|
||||
}
|
||||
(List (Option a))
|
||||
| MouseEnteredOption Int
|
||||
| KeyDown (List (Option a)) String
|
||||
| KeyDown Bool (List (Option a)) String
|
||||
| GotContainerAndMenuElements (Result Dom.Error { menu : Dom.Viewport, container : Dom.Element })
|
||||
| ClearButtonPressed
|
||||
| InputDebounceReturned String
|
||||
|
@ -33,7 +33,13 @@ update_ { request, requestMinInputLength, debounceRequest } tagger msg model =
|
||||
InputChanged val ->
|
||||
( model
|
||||
|> Model.setInputValue val
|
||||
|> Model.highlightIndex 0
|
||||
|> Model.highlightIndex
|
||||
(if String.isEmpty val then
|
||||
Nothing
|
||||
|
||||
else
|
||||
Just 0
|
||||
)
|
||||
|> Model.applyFilter True
|
||||
|> Model.setSelected Nothing
|
||||
|> Model.setItems
|
||||
@ -79,12 +85,12 @@ update_ { request, requestMinInputLength, debounceRequest } tagger msg model =
|
||||
)
|
||||
|
||||
MouseEnteredOption i ->
|
||||
( Model.highlightIndex i model
|
||||
( Model.highlightIndex (Just i) model
|
||||
, Effect.none
|
||||
)
|
||||
|
||||
KeyDown filteredOptions key ->
|
||||
handleKey tagger model key filteredOptions
|
||||
KeyDown selectOnTab filteredOptions key ->
|
||||
handleKey selectOnTab tagger model key filteredOptions
|
||||
|
||||
GotContainerAndMenuElements result ->
|
||||
( model
|
||||
@ -148,7 +154,7 @@ update_ { request, requestMinInputLength, debounceRequest } tagger msg model =
|
||||
onFocusMenu : (Msg a -> msg) -> Bool -> Model a -> ( Model a, Effect effect msg )
|
||||
onFocusMenu tagger hasRequest model =
|
||||
( Model.setFocused True model
|
||||
|> Model.highlightIndex 0
|
||||
|> Model.highlightIndex Nothing
|
||||
, if not hasRequest || Model.toRequestState model == Just Success then
|
||||
Effect.batch
|
||||
[ Effect.ScrollMenuToTop (tagger NoOp) (Model.toMenuElementId model)
|
||||
@ -160,32 +166,43 @@ onFocusMenu tagger hasRequest model =
|
||||
)
|
||||
|
||||
|
||||
handleKey : (Msg a -> msg) -> Model a -> String -> List (Option a) -> ( Model a, Effect effect msg )
|
||||
handleKey tagger model key filteredOptions =
|
||||
case key of
|
||||
"ArrowDown" ->
|
||||
moveHighlight tagger (Basics.min (List.length filteredOptions - 1) (Model.toHighlighted model + 1)) model
|
||||
|
||||
"ArrowUp" ->
|
||||
moveHighlight tagger (Basics.max 0 (Model.toHighlighted model - 1)) model
|
||||
|
||||
"PageDown" ->
|
||||
moveHighlight tagger (Basics.min (List.length filteredOptions - 1) (Model.toHighlighted model + 10)) model
|
||||
|
||||
"PageUp" ->
|
||||
moveHighlight tagger (Basics.max 0 (Model.toHighlighted model - 10)) model
|
||||
|
||||
"Enter" ->
|
||||
case getAt (Model.toHighlighted model) filteredOptions of
|
||||
handleKey : Bool -> (Msg a -> msg) -> Model a -> String -> List (Option a) -> ( Model a, Effect effect msg )
|
||||
handleKey selectOnTab tagger model key filteredOptions =
|
||||
let
|
||||
selectHighlighted =
|
||||
case Model.toHighlighted model |> Maybe.andThen (\idx -> getAt idx filteredOptions) of
|
||||
Just opt ->
|
||||
( Model.selectOption opt model, Effect.none )
|
||||
|
||||
Nothing ->
|
||||
( Model.closeMenu model, Effect.none )
|
||||
in
|
||||
case key of
|
||||
"ArrowDown" ->
|
||||
moveHighlight tagger (Basics.min (List.length filteredOptions - 1) (Maybe.withDefault -1 (Model.toHighlighted model) + 1)) model
|
||||
|
||||
"ArrowUp" ->
|
||||
moveHighlight tagger (Basics.max 0 (Maybe.withDefault 0 (Model.toHighlighted model) - 1)) model
|
||||
|
||||
"PageDown" ->
|
||||
moveHighlight tagger (Basics.min (List.length filteredOptions - 1) (Maybe.withDefault -1 (Model.toHighlighted model) + 10)) model
|
||||
|
||||
"PageUp" ->
|
||||
moveHighlight tagger (Basics.max 0 (Maybe.withDefault 0 (Model.toHighlighted model) - 10)) model
|
||||
|
||||
"Enter" ->
|
||||
selectHighlighted
|
||||
|
||||
"Escape" ->
|
||||
( Model.closeMenu model, Effect.none )
|
||||
|
||||
"Tab" ->
|
||||
if selectOnTab then
|
||||
selectHighlighted
|
||||
|
||||
else
|
||||
( model, Effect.none )
|
||||
|
||||
_ ->
|
||||
( model, Effect.none )
|
||||
|
||||
@ -193,7 +210,7 @@ handleKey tagger model key filteredOptions =
|
||||
moveHighlight : (Msg a -> msg) -> Int -> Model a -> ( Model a, Effect effect msg )
|
||||
moveHighlight tagger newHighlighted model =
|
||||
if Model.isOpen model then
|
||||
( Model.highlightIndex newHighlighted model
|
||||
( Model.highlightIndex (Just newHighlighted) model
|
||||
, Effect.batch
|
||||
[ getContainerAndMenuElementsEffect tagger model
|
||||
, Effect.GetElementsAndScrollMenu
|
||||
|
@ -41,6 +41,7 @@ type alias ViewConfigInternal a msg =
|
||||
, positionFixed : Bool
|
||||
, clearInputValueOnBlur : Bool
|
||||
, selectExactMatchOnBlur : Bool
|
||||
, selectOnTab : Bool
|
||||
}
|
||||
|
||||
|
||||
@ -70,6 +71,7 @@ view attribs v =
|
||||
, positionFixed = False
|
||||
, clearInputValueOnBlur = False
|
||||
, selectExactMatchOnBlur = False
|
||||
, selectOnTab = True
|
||||
}
|
||||
|
||||
|
||||
@ -146,7 +148,7 @@ inputView filteredOptions model config =
|
||||
filteredOptions
|
||||
)
|
||||
)
|
||||
, onKeyDown (Model.isOpen model) (KeyDown filteredOptions >> config.onChange)
|
||||
, onKeyDown (Model.isOpen model) (KeyDown config.selectOnTab filteredOptions >> config.onChange)
|
||||
, Element.htmlAttribute (Html.Attributes.id <| Model.toInputElementId model)
|
||||
, Element.inFront <|
|
||||
if Model.toValue model /= Nothing || Model.toInputValue model /= "" then
|
||||
@ -177,7 +179,9 @@ inputAccessibilityAttributes filteredOptions model =
|
||||
, htmlAttribute "aria-autocomplete" "list"
|
||||
, htmlAttribute "aria-activedescendant" <|
|
||||
if Model.isOpen model then
|
||||
Model.toOptionElementId model (Model.toHighlighted model)
|
||||
Model.toHighlighted model
|
||||
|> Maybe.map (Model.toOptionElementId model)
|
||||
|> Maybe.withDefault ""
|
||||
|
||||
else
|
||||
""
|
||||
|
@ -5,7 +5,7 @@ module Select exposing
|
||||
, isMenuOpen, isLoading, isRequestFailed, isFocused
|
||||
, Msg, update, updateWith
|
||||
, UpdateOption, request, requestMinInputLength, requestDebounceDelay, onSelectedChange, gotRequestResponse
|
||||
, ViewConfig, view, withMenuAttributes, MenuPlacement(..), withMenuMaxHeight, withMenuMaxWidth, withNoMatchElement, withOptionElement, OptionState, withClearButton, ClearButton, clearButton, withFilter, withMenuAlwaysAbove, withMenuAlwaysBelow, withMenuPlacementAuto, withMenuPositionFixed, withClearInputValueOnBlur, withSelectExactMatchOnBlur
|
||||
, ViewConfig, view, withMenuAttributes, MenuPlacement(..), withMenuMaxHeight, withMenuMaxWidth, withNoMatchElement, withOptionElement, OptionState, withClearButton, ClearButton, clearButton, withFilter, withMenuAlwaysAbove, withMenuAlwaysBelow, withMenuPlacementAuto, withMenuPositionFixed, withClearInputValueOnBlur, withSelectExactMatchOnBlur, withSelectOnTab
|
||||
, toElement
|
||||
, Effect
|
||||
)
|
||||
@ -45,7 +45,7 @@ module Select exposing
|
||||
|
||||
# Configure View
|
||||
|
||||
@docs ViewConfig, view, withMenuAttributes, MenuPlacement, withMenuMaxHeight, withMenuMaxWidth, withNoMatchElement, withOptionElement, OptionState, withClearButton, ClearButton, clearButton, withFilter, withMenuAlwaysAbove, withMenuAlwaysBelow, withMenuPlacementAuto, withMenuPositionFixed, withClearInputValueOnBlur, withSelectExactMatchOnBlur
|
||||
@docs ViewConfig, view, withMenuAttributes, MenuPlacement, withMenuMaxHeight, withMenuMaxWidth, withNoMatchElement, withOptionElement, OptionState, withClearButton, ClearButton, clearButton, withFilter, withMenuAlwaysAbove, withMenuAlwaysBelow, withMenuPlacementAuto, withMenuPositionFixed, withClearInputValueOnBlur, withSelectExactMatchOnBlur, withSelectOnTab
|
||||
|
||||
|
||||
# Element
|
||||
@ -545,6 +545,13 @@ withSelectExactMatchOnBlur v (ViewConfig config) =
|
||||
ViewConfig { config | selectExactMatchOnBlur = v }
|
||||
|
||||
|
||||
{-| Should we select the highlighted option when the TAB key is pressed?
|
||||
-}
|
||||
withSelectOnTab : Bool -> ViewConfig a msg -> ViewConfig a msg
|
||||
withSelectOnTab v (ViewConfig config) =
|
||||
ViewConfig { config | selectOnTab = v }
|
||||
|
||||
|
||||
{-| Turn the ViewConfig into an Element.
|
||||
-}
|
||||
toElement : Select a -> ViewConfig a msg -> Element msg
|
||||
|
Loading…
Reference in New Issue
Block a user