module Halogen.HTML
  ( ComponentHTML
  , PlainHTML
  , fromPlainHTML
  , mapHTMLAction
  , slot
  , slot_
  , memoized
  , lazy
  -- , lazy2
  -- , lazy3
  , module Halogen.HTML.Core
  , module Halogen.HTML.Elements
  , module Halogen.HTML.Properties
  )
where

{- attrNS, -}

import Data.Foreign
import Data.Row
import HPrelude
import Halogen.Component
import Halogen.Data.Slot (Slot)
import Halogen.HTML.Core (AttrName (..), ClassName (..), ElemName (..), HTML (..), IsProp (..), Namespace (..), PropName (..), handler, text)
import Halogen.HTML.Core qualified as Core
import Halogen.HTML.Elements
import Halogen.HTML.Properties (IProp, attr, prop)
import Halogen.VDom.Thunk

-- | A convenience synonym for the output type of a `render` function for a
-- | component that renders HTML.
-- |
-- | - `action` is the type of actions, events internal to the component that can
-- |   be evaluated with the `handleAction` function
-- | - `slots` is the set of child component types that can be used in the HTML
-- | - `m` is the monad used by the child component during evaluation
type ComponentHTML action slots m = HTML (ComponentSlot slots m action) action

mapHTMLAction :: forall a a' slots m. (a -> a') -> ComponentHTML a slots m -> ComponentHTML a' slots m
mapHTMLAction :: forall a a' (slots :: Row (*)) (m :: * -> *).
(a -> a') -> ComponentHTML a slots m -> ComponentHTML a' slots m
mapHTMLAction a -> a'
f = (ComponentSlot slots m a -> ComponentSlot slots m a')
-> (a -> a')
-> HTML (ComponentSlot slots m a) a
-> HTML (ComponentSlot slots m a') a'
forall a b c d. (a -> b) -> (c -> d) -> HTML a c -> HTML b d
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap ((a -> a') -> ComponentSlot slots m a -> ComponentSlot slots m a'
forall a b.
(a -> b) -> ComponentSlot slots m a -> ComponentSlot slots m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> a'
f) a -> a'
f

-- | A type useful for a chunk of HTML with no slot-embedding or query-raising.
-- |
-- | Often a polymorphic usage of `HTML` is good enough for this, but sometimes
-- | it's useful to have a type like this (and accompanying coercion) when doing
-- | things like creating components that accept a chunk of HTML as part of
-- | their configuration.
type PlainHTML = HTML Void Void

-- | Relaxes the type of `PlainHTML` to make it compatible with all `HTML`.
fromPlainHTML :: forall w i. PlainHTML -> HTML w i
fromPlainHTML :: forall w i. PlainHTML -> HTML w i
fromPlainHTML = (Void -> w) -> (Void -> i) -> PlainHTML -> HTML w i
forall a b c d. (a -> b) -> (c -> d) -> HTML a c -> HTML b d
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap Void -> w
forall a. Void -> a
absurd Void -> i
forall a. Void -> a
absurd

-- | Defines a slot for a child component. Takes:
-- | - the slot address label
-- | - the slot address index
-- | - the component for the slot
-- | - the input value to pass to the component
-- | - a function mapping outputs from the component to a query in the parent
slot
  :: forall label
    ->forall query action input output slots m slot
   . (HasType label (Slot query output slot) slots, KnownSymbol label, Ord slot)
  => slot
  -> Component query input output m
  -> input
  -> (output -> action)
  -> ComponentHTML action slots m
slot :: forall (label :: Symbol) ->
forall (query :: * -> *) action input output (slots :: Row (*))
       (m :: * -> *) slot.
(HasType label (Slot query output slot) slots, KnownSymbol label,
 Ord slot) =>
slot
-> Component query input output m
-> input
-> (output -> action)
-> ComponentHTML action slots m
slot label' slot
p' Component query input output m
component input
_input output -> action
outputQuery =
  ComponentSlot slots m action
-> HTML (ComponentSlot slots m action) action
forall p q. p -> HTML p q
Core.widget (ComponentSlotBox slots m action -> ComponentSlot slots m action
forall (slots :: Row (*)) (m :: * -> *) msg.
ComponentSlotBox slots m msg -> ComponentSlot slots m msg
ComponentSlot (slot
-> Component query input output m
-> input
-> (output -> Maybe action)
-> ComponentSlotBox slots m action
forall (label :: Symbol) ->
forall (query :: * -> *) input output (slots :: Row (*))
       (m :: * -> *) action slot.
(HasType label (Slot query output slot) slots, KnownSymbol label,
 Ord slot) =>
slot
-> Component query input output m
-> input
-> (output -> Maybe action)
-> ComponentSlotBox slots m action
forall (query :: * -> *) input output (slots :: Row (*))
       (m :: * -> *) action slot.
(HasType label (Slot query output slot) slots, KnownSymbol label,
 Ord slot) =>
slot
-> Component query input output m
-> input
-> (output -> Maybe action)
-> ComponentSlotBox slots m action
componentSlot label' slot
p' Component query input output m
component input
_input (action -> Maybe action
forall a. a -> Maybe a
Just (action -> Maybe action)
-> (output -> action) -> output -> Maybe action
forall b c a. (b -> c) -> (a -> b) -> a -> c
. output -> action
outputQuery)))

-- | Defines a slot for a child component, ignoring its output.
-- |
-- | This variant may be used when the component produces output, but it is not
-- | needed in the current context, or instead of passing `absurd` to `slot`
-- | when the output type is `Void`.
-- |
-- | Takes:
-- | - the slot address label
-- | - the slot address index
-- | - the component for the slot
-- | - the input value to pass to the component
slot_
  :: forall label
    ->forall query action input output slots m slot
   . (HasType label (Slot query output slot) slots, KnownSymbol label, Ord slot)
  => slot
  -> Component query input output m
  -> input
  -> ComponentHTML action slots m
slot_ :: forall (label :: Symbol) ->
forall (query :: * -> *) action input output (slots :: Row (*))
       (m :: * -> *) slot.
(HasType label (Slot query output slot) slots, KnownSymbol label,
 Ord slot) =>
slot
-> Component query input output m
-> input
-> ComponentHTML action slots m
slot_ label' slot
p' Component query input output m
component input
_input =
  ComponentSlot slots m action
-> HTML (ComponentSlot slots m action) action
forall p q. p -> HTML p q
Core.widget (ComponentSlotBox slots m action -> ComponentSlot slots m action
forall (slots :: Row (*)) (m :: * -> *) msg.
ComponentSlotBox slots m msg -> ComponentSlot slots m msg
ComponentSlot (slot
-> Component query input output m
-> input
-> (output -> Maybe action)
-> ComponentSlotBox slots m action
forall (label :: Symbol) ->
forall (query :: * -> *) input output (slots :: Row (*))
       (m :: * -> *) action slot.
(HasType label (Slot query output slot) slots, KnownSymbol label,
 Ord slot) =>
slot
-> Component query input output m
-> input
-> (output -> Maybe action)
-> ComponentSlotBox slots m action
forall (query :: * -> *) input output (slots :: Row (*))
       (m :: * -> *) action slot.
(HasType label (Slot query output slot) slots, KnownSymbol label,
 Ord slot) =>
slot
-> Component query input output m
-> input
-> (output -> Maybe action)
-> ComponentSlotBox slots m action
componentSlot label' slot
p' Component query input output m
component input
_input (Maybe action -> output -> Maybe action
forall a b. a -> b -> a
const Maybe action
forall a. Maybe a
Nothing)))

-- | Optimizes rendering of a subtree given an equality predicate. If an argument
-- | is deemed equivalent to the previous value, rendering and diffing will be
-- | skipped. You should not use this function fully saturated, but instead
-- | partially apply it for use within a Component's scope. For example, to skip
-- | rendering for equal states, just wrap your `render` function.
-- |
-- | ```purescript
-- | myComponent = component
-- |  { render: memoized eq render
-- |  , ...
-- |  }
-- | ```
memoized
  :: forall a action slots m
   . (a -> a -> Bool)
  -> (a -> ComponentHTML action slots m)
  -> a
  -> ComponentHTML action slots m
memoized :: forall a action (slots :: Row (*)) (m :: * -> *).
(a -> a -> Bool)
-> (a -> ComponentHTML action slots m)
-> a
-> ComponentHTML action slots m
memoized a -> a -> Bool
eqFn a -> ComponentHTML action slots m
f =
  -- Note: This implementation must not be eta-expanded, as it relies on
  -- partial application to work.
  ComponentSlot slots m action -> ComponentHTML action slots m
forall p q. p -> HTML p q
Core.widget (ComponentSlot slots m action -> ComponentHTML action slots m)
-> (Thunk (HTML (ComponentSlot slots m action)) action
    -> ComponentSlot slots m action)
-> Thunk (HTML (ComponentSlot slots m action)) action
-> ComponentHTML action slots m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Thunk (HTML (ComponentSlot slots m action)) action
-> ComponentSlot slots m action
forall (slots :: Row (*)) (m :: * -> *) msg.
Thunk (HTML (ComponentSlot slots m msg)) msg
-> ComponentSlot slots m msg
ThunkSlot (Thunk (HTML (ComponentSlot slots m action)) action
 -> ComponentHTML action slots m)
-> (a -> Thunk (HTML (ComponentSlot slots m action)) action)
-> a
-> ComponentHTML action slots m
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ThunkId
-> (a -> a -> Bool)
-> (a -> ComponentHTML action slots m)
-> a
-> Thunk (HTML (ComponentSlot slots m action)) action
forall {k} (f :: k -> *) (i :: k) a.
ThunkId -> (a -> a -> Bool) -> (a -> f i) -> a -> Thunk f i
Thunk ((a -> ComponentHTML action slots m) -> ThunkId
forall a. a -> ThunkId
unsafeThunkId a -> ComponentHTML action slots m
f) a -> a -> Bool
eqFn a -> ComponentHTML action slots m
f

-- | Skips rendering for referentially equal arguments. You should not use this
-- | function fully saturated, but instead partially apply it for use within a
-- | Component's scope.
lazy
  :: forall a action slots m
   . (a -> ComponentHTML action slots m)
  -> a
  -> ComponentHTML action slots m
lazy :: forall a action (slots :: Row (*)) (m :: * -> *).
(a -> ComponentHTML action slots m)
-> a -> ComponentHTML action slots m
lazy = (a -> a -> Bool)
-> (a -> ComponentHTML action slots m)
-> a
-> ComponentHTML action slots m
forall a action (slots :: Row (*)) (m :: * -> *).
(a -> a -> Bool)
-> (a -> ComponentHTML action slots m)
-> a
-> ComponentHTML action slots m
memoized a -> a -> Bool
forall a. a -> a -> Bool
unsafeRefEq

{-
-- | Like `lazy`, but for a rendering function which takes 2 arguments.
lazy2
  :: forall a b action slots m
   . (a -> b -> ComponentHTML action slots m)
  -> a
  -> b
  -> ComponentHTML action slots m
lazy2 f a b = Core.widget (ThunkSlot (Fn.runFn3 thunk2 f a b))

-- | Like `lazy`, but for a rendering function which takes 3 arguments.
lazy3
  :: forall a b c action slots m
   . (a -> b -> c -> ComponentHTML action slots m)
  -> a
  -> b
  -> c
  -> ComponentHTML action slots m
lazy3 f a b c = Core.widget (ThunkSlot (Fn.runFn4 thunk3 f a b c))
-}