|
|
@@ -22,39 +22,58 @@ import Data.Time.Duration (Milliseconds(..)) |
|
|
|
import Data.Traversable (traverse_) |
|
|
|
import Data.Tuple (Tuple(..)) |
|
|
|
import Data.Newtype (class Newtype, unwrap) |
|
|
|
import Data.Symbol (SProxy(..)) |
|
|
|
import DOM (DOM) |
|
|
|
import DOM.Event.Event (preventDefault, currentTarget) |
|
|
|
import DOM.Event.Types as ET |
|
|
|
import DOM.Event.KeyboardEvent as KE |
|
|
|
import DOM.Event.MouseEvent as ME |
|
|
|
import DOM.HTML.HTMLElement (blur, focus) |
|
|
|
import DOM.HTML.Types (HTMLElement, readHTMLElement) |
|
|
|
import Halogen (Component, ComponentDSL, ComponentHTML, component, liftAff, liftEff, modify) as H |
|
|
|
import Halogen as H |
|
|
|
import Halogen.HTML as HH |
|
|
|
import Halogen.HTML.Events as HE |
|
|
|
import Halogen.Query.HalogenM (fork, raise) as H |
|
|
|
import Select.Internal.State (updateStore, getState) |
|
|
|
|
|
|
|
---------- |
|
|
|
-- Component Types |
|
|
|
|
|
|
|
-- | A useful shorthand for the Halogen component type |
|
|
|
type Component o item eff m |
|
|
|
= H.Component HH.HTML (Query o item eff) (Input o item eff) (Message o item) m |
|
|
|
= H.Component HH.HTML (Query o item eff m) (Input o item eff m) (Message o item) m |
|
|
|
|
|
|
|
-- | A useful shorthand for the Halogen component HTML type |
|
|
|
type ComponentHTML o item eff |
|
|
|
= H.ComponentHTML (Query o item eff) |
|
|
|
type ComponentHTML o item eff m |
|
|
|
= H.ComponentHTML (Query o item eff m) () m |
|
|
|
|
|
|
|
-- | A useful shorthand for the Halogen component DSL type |
|
|
|
type ComponentDSL o item eff m |
|
|
|
= H.ComponentDSL (StateStore o item eff) (Query o item eff) (Message o item) m |
|
|
|
= H.HalogenM (StateStore o item eff m) (Query o item eff m) () (Message o item) m |
|
|
|
|
|
|
|
-- | The component slot type for convenience. Partially applied so you |
|
|
|
-- | can still provide your own reference for slots. |
|
|
|
type Slot o item eff m |
|
|
|
= H.Slot (Query o item eff m) (Message o item) |
|
|
|
|
|
|
|
-- | The symbol for this component in the slot row |
|
|
|
_select :: SProxy "select" |
|
|
|
_select = SProxy :: SProxy "select" |
|
|
|
|
|
|
|
-- | A helper function to mount the Select component in a slot |
|
|
|
select :: ∀ p o item eff m r |
|
|
|
. Ord p |
|
|
|
=> MonadAff (Effects eff) m |
|
|
|
=> p |
|
|
|
-> Input o item (Effects eff) m |
|
|
|
-> (Message o item -> Maybe (o Unit)) |
|
|
|
-> H.ComponentHTML o ( select :: Slot o item (Effects eff) m p | r ) m |
|
|
|
select slot i handler = HH.slot (SProxy :: SProxy "select") slot component i handler |
|
|
|
|
|
|
|
-- | The component's state type, wrapped in `Store`. The state and result of the |
|
|
|
-- | render function are stored so that `extract` from `Control.Comonad` can be |
|
|
|
-- | used to pull out the render function. |
|
|
|
type StateStore o item eff |
|
|
|
= Store (State item eff) (ComponentHTML o item eff) |
|
|
|
type StateStore o item eff m |
|
|
|
= Store (State item eff) (ComponentHTML o item eff m) |
|
|
|
|
|
|
|
-- | The effects necessary for this component to run. Your component will need to |
|
|
|
-- | also support these effects. |
|
|
@@ -92,7 +111,7 @@ type Effects eff = ( avar :: AVAR, dom :: DOM | eff ) |
|
|
|
-- | own queries. Triggers an `Emit` message containing the query when triggered. |
|
|
|
-- | This can be used to easily extend `Select` with more behaviors. |
|
|
|
-- | - `Receive`: Sets the component with new input |
|
|
|
data Query o item eff a |
|
|
|
data Query o item eff m a |
|
|
|
= Search String a |
|
|
|
| Highlight Target a |
|
|
|
| Select Int a |
|
|
@@ -103,9 +122,9 @@ data Query o item eff a |
|
|
|
| SetVisibility Visibility a |
|
|
|
| ToggleVisibility a |
|
|
|
| ReplaceItems (Array item) a |
|
|
|
| AndThen (DayPair (Query o item eff) a) |
|
|
|
| AndThen (DayPair (Query o item eff m) a) |
|
|
|
| Raise (o Unit) a |
|
|
|
| Receive (Input o item eff) a |
|
|
|
| Receive (Input o item eff m) a |
|
|
|
|
|
|
|
-- | A type representing a pair of queries that can be run in order. |
|
|
|
newtype DayPair f a = DayPair (Day f f a) |
|
|
@@ -120,7 +139,7 @@ derive instance newtypeDayPair :: Newtype (DayPair f a) _ |
|
|
|
-- | TriggerFocus a |
|
|
|
-- | ] |
|
|
|
-- | ``` |
|
|
|
andThen :: ∀ o item eff a. Query o item eff Unit -> Query o item eff a -> Query o item eff a |
|
|
|
andThen :: ∀ o item eff m a. Query o item eff m Unit -> Query o item eff m a -> Query o item eff m a |
|
|
|
andThen q1 q2 = AndThen $ DayPair $ day (const id) q1 q2 |
|
|
|
|
|
|
|
-- | Represents a way to navigate on `Highlight` events: to the previous |
|
|
@@ -181,12 +200,12 @@ type Debouncer eff = |
|
|
|
-- | The component's input type, which includes the component`s render function. This |
|
|
|
-- | render function can also be used to share data with the parent component, as every |
|
|
|
-- | time the parent re-renders, the render function will refresh in `Select`. |
|
|
|
type Input o item eff = |
|
|
|
type Input o item eff m = |
|
|
|
{ inputType :: InputType |
|
|
|
, items :: Array item |
|
|
|
, initialSearch :: Maybe String |
|
|
|
, debounceTime :: Maybe Milliseconds |
|
|
|
, render :: State item eff -> ComponentHTML o item eff |
|
|
|
, render :: State item eff -> ComponentHTML o item eff m |
|
|
|
} |
|
|
|
|
|
|
|
-- | The parent is only notified for a few important events, but `Emit` makes it |
|
|
@@ -211,6 +230,8 @@ component = |
|
|
|
{ initialState |
|
|
|
, render: extract |
|
|
|
, eval |
|
|
|
, initializer: Nothing |
|
|
|
, finalizer: Nothing |
|
|
|
, receiver: HE.input Receive |
|
|
|
} |
|
|
|
where |
|
|
@@ -226,7 +247,7 @@ component = |
|
|
|
, lastIndex: length i.items - 1 |
|
|
|
} |
|
|
|
|
|
|
|
eval :: (Query o item (Effects eff)) ~> ComponentDSL o item (Effects eff) m |
|
|
|
eval :: (Query o item (Effects eff) m) ~> ComponentDSL o item (Effects eff) m |
|
|
|
eval = case _ of |
|
|
|
Search str a -> a <$ do |
|
|
|
(Tuple _ st) <- getState |
|
|
|