1
Fork 0

Cleanup examples by putting input and specs in a where clause

This commit is contained in:
Jordan Martinez 2019-05-18 20:42:08 -07:00
commit aac003ecc0
2 changed files with 192 additions and 193 deletions
examples/Components

View file

@ -33,52 +33,54 @@ type Input =
}
component :: H.Component HH.HTML S.Query' Input Message Aff
component = S.component input spec
input :: Input -> S.Input State
input { items, buttonLabel } =
{ inputType: S.Toggle
, search: Nothing
, debounceTime: Nothing
, getItemCount: length <<< _.items
, items
, buttonLabel
, selection: Nothing
}
spec :: S.Spec State (Const Void) Void () Message Aff
spec = S.defaultSpec { render = render, handleMessage = handleMessage }
component = S.component input $ S.defaultSpec
{ render = render
, handleMessage = handleMessage
}
where
handleMessage = case _ of
S.Selected ix -> do
st <- H.get
let selection = st.items !! ix
H.modify_ _ { selection = selection, visibility = S.Off }
H.raise $ SelectionChanged st.selection selection
_ -> pure unit
input :: Input -> S.Input State
input { items, buttonLabel } =
{ inputType: S.Toggle
, search: Nothing
, debounceTime: Nothing
, getItemCount: length <<< _.items
, items
, buttonLabel
, selection: Nothing
}
render st =
HH.div
[ class_ "Dropdown" ]
[ renderToggle, renderContainer ]
where
renderToggle =
HH.button
( SS.setToggleProps [ class_ "Dropdown__toggle" ] )
[ HH.text (fromMaybe st.buttonLabel st.selection) ]
handleMessage :: S.Message -> H.HalogenM (S.State State) S.Action' Message Aff Unit
handleMessage = case _ of
S.Selected ix -> do
st <- H.get
let selection = st.items !! ix
H.modify_ _ { selection = selection, visibility = S.Off }
H.raise $ SelectionChanged st.selection selection
_ -> pure unit
renderContainer = whenElem (st.visibility == S.On) \_ ->
render :: S.State State -> H.ComponentHTML S.Action' () Aff
render st =
HH.div
( SS.setContainerProps [ class_ "Dropdown__container" ] )
( renderItem `mapWithIndex` st.items )
[ class_ "Dropdown" ]
[ renderToggle, renderContainer ]
where
renderItem index item =
renderToggle =
HH.button
( SS.setToggleProps [ class_ "Dropdown__toggle" ] )
[ HH.text (fromMaybe st.buttonLabel st.selection) ]
renderContainer = whenElem (st.visibility == S.On) \_ ->
HH.div
( SS.setItemProps index
[ classes_
[ "Dropdown__item"
, "Dropdown__item--highlighted" # guard (st.highlightedIndex == Just index)
]
]
)
[ HH.text item ]
( SS.setContainerProps [ class_ "Dropdown__container" ] )
( renderItem `mapWithIndex` st.items )
where
renderItem index item =
HH.div
( SS.setItemProps index
[ classes_
[ "Dropdown__item"
, "Dropdown__item--highlighted" # guard (st.highlightedIndex == Just index)
]
]
)
[ HH.text item ]

View file

@ -47,165 +47,162 @@ type ChildSlots =
( dropdown :: D.Slot Unit )
component :: H.Component HH.HTML (S.Query Query ChildSlots) Unit Message Aff
component = S.component (const input) spec
-- this typeahead will be opaque; users can just use this pre-built
-- input instead of the usual select one.
input :: S.Input State
input =
{ inputType: S.Text
, debounceTime: Just (Milliseconds 300.0)
, search: Nothing
, getItemCount: maybe 0 length <<< RD.toMaybe <<< _.available
, selections: []
, available: RD.NotAsked
}
spec :: S.Spec State Query Action ChildSlots Message Aff
spec = S.defaultSpec
{ render = render
, handleAction = handleAction
, handleQuery = handleQuery
, handleMessage = handleMessage
}
component = S.component (const input) $ S.defaultSpec
{ render = render
, handleAction = handleAction
, handleQuery = handleQuery
, handleMessage = handleMessage
}
where
handleMessage
:: S.Message
-> H.HalogenM (S.State State) (S.Action Action) ChildSlots Message Aff Unit
handleMessage = case _ of
S.Selected ix -> do
st <- H.get
for_ st.available \arr ->
for_ (arr !! ix) \item -> do
let newSelections = item : st.selections
H.modify_ _
{ selections = item : st.selections
, available = RD.Success (filter (_ /= item) arr)
, search = ""
}
H.raise $ SelectionsChanged newSelections
S.Searched str -> do
st <- H.get
-- we'll use an external api to search locations
H.modify_ _ { available = RD.Loading }
items <- H.liftAff $ searchLocations str
H.modify_ _ { available = items <#> \xs -> difference xs st.selections }
_ -> pure unit
-- this typeahead will be opaque; users can just use this pre-built
-- input instead of the usual select one.
input :: S.Input State
input =
{ inputType: S.Text
, debounceTime: Just (Milliseconds 300.0)
, search: Nothing
, getItemCount: maybe 0 length <<< RD.toMaybe <<< _.available
, selections: []
, available: RD.NotAsked
}
-- You can remove all type signatures except for this one; we need to tell the
-- compiler about the `a` type variable. The minimal necessary signature is below.
handleQuery :: forall a. Query a -> H.HalogenM _ _ _ _ _ (Maybe a)
handleQuery = case _ of
GetSelections reply -> do
st <- H.get
pure $ Just $ reply st.selections
handleAction
:: Action
-> H.HalogenM (S.State State) (S.Action Action) ChildSlots Message Aff Unit
handleAction = case _ of
Remove item -> do
st <- H.get
let newSelections = filter (_ /= item) st.selections
H.modify_ _ { selections = newSelections }
H.raise $ ItemRemoved item
HandleDropdown msg -> case msg of
D.SelectionChanged oldSelection newSelection -> do
handleMessage
:: S.Message
-> H.HalogenM (S.State State) (S.Action Action) ChildSlots Message Aff Unit
handleMessage = case _ of
S.Selected ix -> do
st <- H.get
let
mkLocation str = { name: "User Added: " <> str, population: "1" }
newSelections = case oldSelection, newSelection of
Nothing, Nothing ->
Nothing
Nothing, Just str ->
Just (mkLocation str : st.selections)
Just str, Nothing ->
Just (filter (_ /= mkLocation str) st.selections)
Just old, Just new ->
Just (mkLocation new : (filter (_ /= mkLocation old) st.selections))
for_ newSelections \selections ->
H.modify_ _ { selections = selections }
for_ st.available \arr ->
for_ (arr !! ix) \item -> do
let newSelections = item : st.selections
H.modify_ _
{ selections = item : st.selections
, available = RD.Success (filter (_ /= item) arr)
, search = ""
}
H.raise $ SelectionsChanged newSelections
S.Searched str -> do
st <- H.get
-- we'll use an external api to search locations
H.modify_ _ { available = RD.Loading }
items <- H.liftAff $ searchLocations str
H.modify_ _ { available = items <#> \xs -> difference xs st.selections }
_ -> pure unit
render :: S.State State -> H.ComponentHTML (S.Action Action) ChildSlots Aff
render st =
HH.div
[ class_ "Typeahead" ]
[ renderSelections, renderInput, renderDropdown, renderContainer ]
where
hasSelections = length st.selections > 0
-- You can remove all type signatures except for this one; we need to tell the
-- compiler about the `a` type variable. The minimal necessary signature is below.
handleQuery :: forall a. Query a -> H.HalogenM _ _ _ _ _ (Maybe a)
handleQuery = case _ of
GetSelections reply -> do
st <- H.get
pure $ Just $ reply st.selections
renderSelections = whenElem hasSelections \_ ->
handleAction
:: Action
-> H.HalogenM (S.State State) (S.Action Action) ChildSlots Message Aff Unit
handleAction = case _ of
Remove item -> do
st <- H.get
let newSelections = filter (_ /= item) st.selections
H.modify_ _ { selections = newSelections }
H.raise $ ItemRemoved item
HandleDropdown msg -> case msg of
D.SelectionChanged oldSelection newSelection -> do
st <- H.get
let
mkLocation str = { name: "User Added: " <> str, population: "1" }
newSelections = case oldSelection, newSelection of
Nothing, Nothing ->
Nothing
Nothing, Just str ->
Just (mkLocation str : st.selections)
Just str, Nothing ->
Just (filter (_ /= mkLocation str) st.selections)
Just old, Just new ->
Just (mkLocation new : (filter (_ /= mkLocation old) st.selections))
for_ newSelections \selections ->
H.modify_ _ { selections = selections }
render :: S.State State -> H.ComponentHTML (S.Action Action) ChildSlots Aff
render st =
HH.div
[ class_ "Typeahead__selections" ]
(renderSelectedItem <$> st.selections)
[ class_ "Typeahead" ]
[ renderSelections, renderInput, renderDropdown, renderContainer ]
where
renderSelectedItem item =
hasSelections = length st.selections > 0
renderSelections = whenElem hasSelections \_ ->
HH.div
[ class_ "Typeahead__item--selected Location" ]
[ HH.span
[ class_ "Location__name" ]
[ HH.text item.name ]
, closeButton item
]
closeButton item =
HH.span
[ class_ "Location__closeButton"
, HE.onClick \_ -> Just $ S.Action $ Remove item
]
[ HH.text "×" ]
renderInput = HH.input $ SS.setInputProps
[ classes_
[ "Typeahead__input"
, "Typeahead__input--selections" # guard hasSelections
, "Typeahead__input--active" # guard (st.visibility == S.On)
]
, HP.placeholder "Type to search..."
]
renderDropdown = whenElem (st.visibility == S.On) \_ ->
HH.slot _dropdown unit D.component dropdownInput handler
where
_dropdown = SProxy :: SProxy "dropdown"
handler msg = Just $ S.Action $ HandleDropdown msg
dropdownInput = { items: [ "Earth", "Mars" ], buttonLabel: "Human Planets" }
renderContainer = whenElem (st.visibility == S.On) \_ ->
HH.div
(SS.setContainerProps
[ classes_
[ "Typeahead__container"
, "Typeahead__container--hasItems" # guard hasItems
]
]
)
renderItems
where
hasItems = maybe false (not <<< null) (RD.toMaybe st.available)
renderItems = do
let renderMsg msg = [ HH.span_ [ HH.text msg ] ]
case st.available of
RD.NotAsked -> renderMsg "No search performed..."
RD.Loading -> renderMsg "Loading..."
RD.Failure e -> renderMsg e
RD.Success available
| hasItems -> renderItem `mapWithIndex` available
| otherwise -> renderMsg "No results found"
renderItem index { name, population } =
HH.div
(SS.setItemProps index [ classes_ [ base, highlight, "Location" ] ])
[ HH.span
[ class_ "Location__name" ]
[ HH.text name ]
, HH.span
[ class_ "Location__population" ]
[ HH.text population ]
]
[ class_ "Typeahead__selections" ]
(renderSelectedItem <$> st.selections)
where
base = "Typeahead__item"
highlight = "Typeahead__item--highlighted" # guard (st.highlightedIndex == Just index)
renderSelectedItem item =
HH.div
[ class_ "Typeahead__item--selected Location" ]
[ HH.span
[ class_ "Location__name" ]
[ HH.text item.name ]
, closeButton item
]
closeButton item =
HH.span
[ class_ "Location__closeButton"
, HE.onClick \_ -> Just $ S.Action $ Remove item
]
[ HH.text "×" ]
renderInput = HH.input $ SS.setInputProps
[ classes_
[ "Typeahead__input"
, "Typeahead__input--selections" # guard hasSelections
, "Typeahead__input--active" # guard (st.visibility == S.On)
]
, HP.placeholder "Type to search..."
]
renderDropdown = whenElem (st.visibility == S.On) \_ ->
HH.slot _dropdown unit D.component dropdownInput handler
where
_dropdown = SProxy :: SProxy "dropdown"
handler msg = Just $ S.Action $ HandleDropdown msg
dropdownInput = { items: [ "Earth", "Mars" ], buttonLabel: "Human Planets" }
renderContainer = whenElem (st.visibility == S.On) \_ ->
HH.div
(SS.setContainerProps
[ classes_
[ "Typeahead__container"
, "Typeahead__container--hasItems" # guard hasItems
]
]
)
renderItems
where
hasItems = maybe false (not <<< null) (RD.toMaybe st.available)
renderItems = do
let renderMsg msg = [ HH.span_ [ HH.text msg ] ]
case st.available of
RD.NotAsked -> renderMsg "No search performed..."
RD.Loading -> renderMsg "Loading..."
RD.Failure e -> renderMsg e
RD.Success available
| hasItems -> renderItem `mapWithIndex` available
| otherwise -> renderMsg "No results found"
renderItem index { name, population } =
HH.div
(SS.setItemProps index [ classes_ [ base, highlight, "Location" ] ])
[ HH.span
[ class_ "Location__name" ]
[ HH.text name ]
, HH.span
[ class_ "Location__population" ]
[ HH.text population ]
]
where
base = "Typeahead__item"
highlight = "Typeahead__item--highlighted" # guard (st.highlightedIndex == Just index)
-- Let's make this typeahead async.