added: "S" hotkey to focus on search field (#4)

This commit is contained in:
Vladimir Kalnitsky 2019-07-15 23:08:58 +03:00 committed by GitHub
parent 6ba28b3de8
commit e69e81379a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 13 deletions

View File

@ -16,3 +16,9 @@ spago docs
spago bundle-app -m Docs.Search.App --to generated-docs/docs-search-app.js
spago run -m Docs.Search.IndexBuilder
```
## UI
The user interface of the app is optimised for keyboard-only use.
**S** hotkey can be used to focus on the search field, **Escape** can be used to leave it. Pressing **Escape** twice will close the search results listing.

View File

@ -41,7 +41,7 @@ let additions =
, "web-uievents"
]
"https://github.com/slamdata/purescript-halogen.git"
"v5.0.0-rc.4"
"v5.0.0-rc.5"
, halogen-css =
mkPackage
[ "css", "halogen" ]

View File

@ -2,23 +2,38 @@ module Docs.Search.App.SearchField where
import Prelude
import CSS hiding (render, map)
import Data.Maybe (Maybe(..))
import CSS (border, borderRadius, color, em, float, floatLeft, fontWeight, lineHeight, marginBottom, marginLeft, paddingBottom, paddingLeft, paddingRight, paddingTop, pct, px, rgb, solid, weight, width)
import Data.Maybe (Maybe(..), maybe)
import Data.Newtype (wrap)
import Effect (Effect)
import Effect.Aff (Aff)
import Halogen as H
import Halogen.HTML as HH
import Halogen.HTML.CSS as HS
import Halogen.HTML.Events as HE
import Halogen.HTML.Properties as HP
import Halogen.Query.EventSource as ES
import Web.DOM.Document as Document
import Web.DOM.ParentNode as ParentNode
import Web.HTML (window) as Web
import Web.HTML as HTML
import Web.HTML.HTMLDocument as HTMLDocument
import Web.HTML.HTMLElement (blur, focus, fromElement) as Web
import Web.HTML.Window (document) as Web
import Web.HTML.Window as Window
import Web.UIEvent.KeyboardEvent (KeyboardEvent)
import Web.UIEvent.KeyboardEvent as KE
import Web.UIEvent.KeyboardEvent as KeyboardEvent
import Web.UIEvent.KeyboardEvent.EventTypes as KET
type State = { input :: String }
type State = { input :: String, focused :: Boolean }
data Action
= InputAction String
| EnterPressed
| EscapePressed
| FocusChanged Boolean
| InitKeyboardListener
| HandleKey H.SubscriptionId KeyboardEvent
data SearchFieldMessage
= InputUpdated String
@ -31,28 +46,61 @@ component =
H.mkComponent
{ initialState
, render
, eval: H.mkEval $ H.defaultEval { handleAction = handleAction }
, eval: H.mkEval $ H.defaultEval { handleAction = handleAction
, initialize = Just InitKeyboardListener }
}
initialState :: forall i. i -> State
initialState _ = { input: "" }
initialState _ = { input: "", focused: false }
handleAction :: forall m. Action -> H.HalogenM State Action () SearchFieldMessage m Unit
handleAction :: Action -> H.HalogenM State Action () SearchFieldMessage Aff Unit
handleAction = case _ of
InitKeyboardListener -> do
document <- H.liftEffect $ Web.document =<< Web.window
H.subscribe' \sid ->
ES.eventListenerEventSource
KET.keyup
(HTMLDocument.toEventTarget document)
(map (HandleKey sid) <<< KE.fromEvent)
HandleKey sid ev -> do
when (KE.code ev == "KeyS") do
H.liftEffect $ withSearchField Web.focus
when (KE.code ev == "Escape") do
state <- H.get
if state.focused
then H.liftEffect $ withSearchField Web.blur
else do
H.modify_ (_ { input = "" })
H.raise $ InputCleared
InputAction input -> do
H.modify_ $ const { input }
H.modify_ $ (_ { input = input })
EnterPressed -> do
state <- H.get
H.liftEffect $ withSearchField Web.blur
H.raise $ InputUpdated state.input
EscapePressed -> do
H.modify_ (_ { input = "" })
H.raise $ InputCleared
FocusChanged status -> do
H.modify_ (_ { focused = status })
H.raise
if status
then Focused
else LostFocus
withSearchField :: (HTML.HTMLElement -> Effect Unit) -> Effect Unit
withSearchField cont = do
doc <- Document.toParentNode <$>
HTMLDocument.toDocument <$>
(Window.document =<< HTML.window)
let selector = wrap "#docs-search-query-field"
mbEl <- ParentNode.querySelector selector doc
maybe mempty cont (mbEl >>= Web.fromElement)
render :: forall m. State -> H.ComponentHTML Action () m
render state =
HH.div
@ -68,11 +116,11 @@ render state =
[ HH.input
[ HP.value state.input
, HP.placeholder "Search for definitions"
, HP.id_ "docs-search-query-field"
, HP.type_ HP.InputText
, HE.onKeyUp (\event ->
case KeyboardEvent.code event of
"Enter" -> Just EnterPressed
"Escape" -> Just EscapePressed
_ -> Nothing)
, HE.onValueInput (Just <<< InputAction)
, HE.onFocusIn $ const $ Just $ FocusChanged true