-----------------------------------------------------------------------------
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE MultilineStrings  #-}
{-# LANGUAGE RecordWildCards   #-}
{-# LANGUAGE LambdaCase        #-}
-----------------------------------------------------------------------------
module Miso.UI.Dialog
  ( -- ** Props
    DialogProps (..)
  , defaultDialogProps
    -- ** Views
  , dialog_
  , dialogHeader_
  , dialogSection_
  , dialogFooter_
  , dialogCloseButton_
    -- ** Component
  , dialogComponent
    -- ** Samples
  , dialogCodeSample
  , dialogPropsApi
  ) where
-----------------------------------------------------------------------------
import           Control.Monad
-----------------------------------------------------------------------------
import           Miso
import qualified Miso.CSS as CSS
import qualified Miso.Html.Element as H
import qualified Miso.Html.Event as E
import qualified Miso.Html.Property as P
import           Miso.Lens
-----------------------------------------------------------------------------
import           Miso.UI.Button
import           Miso.UI.Icons
import           Miso.UI.Input
import           Miso.UI.Label
import           Miso.UI.Types
-----------------------------------------------------------------------------
-- | Props for 'dialog_' (the native @dialog@ element)
data DialogProps action
  = DialogProps
  { forall action. DialogProps action -> MisoString
dialogId :: MisoString
    -- ^ id of the dialog; @-title@ \/ @-description@ ids derive from it
  , forall action. DialogProps action -> [MisoString]
dialogClasses :: [MisoString]
    -- ^ Extra classes appended to @dialog.dialog@
  , forall action. DialogProps action -> [Attribute action]
dialogAttrs :: [Attribute action]
  }
-----------------------------------------------------------------------------
-- | Smart constructor
defaultDialogProps :: DialogProps action
defaultDialogProps :: forall action. DialogProps action
defaultDialogProps
  = DialogProps
  { dialogId :: MisoString
dialogId = MisoString
"dialog"
  , dialogClasses :: [MisoString]
dialogClasses = [ MisoString
"w-full", MisoString
"sm:max-w-[425px]", MisoString
"max-h-[612px]" ]
  , dialogAttrs :: [Attribute action]
dialogAttrs = []
  }
-----------------------------------------------------------------------------
-- | <https://basecoatui.com/components/dialog/ Dialog>, driven by 'DialogProps'.
-- Children typically include 'dialogHeader_', 'dialogSection_', 'dialogFooter_'
-- and a 'dialogCloseButton_'.
dialog_
  :: DialogProps action
  -> [View model action]
  -> View model action
dialog_ :: forall action model.
DialogProps action -> [View model action] -> View model action
dialog_ DialogProps {[MisoString]
[Attribute action]
MisoString
dialogId :: forall action. DialogProps action -> MisoString
dialogClasses :: forall action. DialogProps action -> [MisoString]
dialogAttrs :: forall action. DialogProps action -> [Attribute action]
dialogId :: MisoString
dialogClasses :: [MisoString]
dialogAttrs :: [Attribute action]
..} [View model action]
kids =
  [Attribute action] -> [View model action] -> View model action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.dialog_
    ( [[Attribute action]] -> [Attribute action]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
      [ [ MisoString -> Attribute action
forall action. MisoString -> Attribute action
P.id_ MisoString
dialogId
        , [MisoString] -> Attribute action
forall action. [MisoString] -> Attribute action
P.classes_ (MisoString
"dialog" MisoString -> [MisoString] -> [MisoString]
forall a. a -> [a] -> [a]
: [MisoString]
dialogClasses)
        , MisoString -> MisoString -> Attribute action
forall action. MisoString -> MisoString -> Attribute action
P.aria_ MisoString
"labelledby" (MisoString
dialogId MisoString -> MisoString -> MisoString
forall a. Semigroup a => a -> a -> a
<> MisoString
"-title")
        , MisoString -> MisoString -> Attribute action
forall action. MisoString -> MisoString -> Attribute action
P.aria_ MisoString
"describedby" (MisoString
dialogId MisoString -> MisoString -> MisoString
forall a. Semigroup a => a -> a -> a
<> MisoString
"-description")
        ]
      , [Attribute action]
dialogAttrs
      ]
    ) [View model action]
kids
-----------------------------------------------------------------------------
-- | Header with title and description (ids derived from the dialog id)
dialogHeader_
  :: MisoString
  -- ^ dialog id (matches 'dialogId')
  -> [View model action]
  -- ^ title
  -> [View model action]
  -- ^ description
  -> View model action
dialogHeader_ :: forall model action.
MisoString
-> [View model action] -> [View model action] -> View model action
dialogHeader_ MisoString
did [View model action]
title [View model action]
description =
  [Attribute action] -> [View model action] -> View model action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.header_ []
  [ [Attribute action] -> [View model action] -> View model action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.h2_ [ MisoString -> Attribute action
forall action. MisoString -> Attribute action
P.id_ (MisoString
did MisoString -> MisoString -> MisoString
forall a. Semigroup a => a -> a -> a
<> MisoString
"-title") ] [View model action]
title
  , [Attribute action] -> [View model action] -> View model action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.p_ [ MisoString -> Attribute action
forall action. MisoString -> Attribute action
P.id_ (MisoString
did MisoString -> MisoString -> MisoString
forall a. Semigroup a => a -> a -> a
<> MisoString
"-description") ] [View model action]
description
  ]
-----------------------------------------------------------------------------
dialogSection_
  :: [Attribute action]
  -> [View model action]
  -> View model action
dialogSection_ :: forall action model.
[Attribute action] -> [View model action] -> View model action
dialogSection_ = [Attribute action] -> [View model action] -> View model action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.section_
-----------------------------------------------------------------------------
dialogFooter_
  :: [Attribute action]
  -> [View model action]
  -> View model action
dialogFooter_ :: forall action model.
[Attribute action] -> [View model action] -> View model action
dialogFooter_ = [Attribute action] -> [View model action] -> View model action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.footer_
-----------------------------------------------------------------------------
-- | The x-shaped close button in the dialog's corner
dialogCloseButton_ :: action -> View model action
dialogCloseButton_ :: forall action model. action -> View model action
dialogCloseButton_ action
close =
  [Attribute action] -> [View model action] -> View model action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.button_
  [ MisoString -> Attribute action
forall action. MisoString -> Attribute action
P.type_ MisoString
"button"
  , MisoString -> MisoString -> Attribute action
forall action. MisoString -> MisoString -> Attribute action
P.aria_ MisoString
"label" MisoString
"Close dialog"
  , [Style] -> Attribute action
forall action. [Style] -> Attribute action
CSS.style_ [ MisoString -> Style
CSS.cursor MisoString
"pointer" ]
  , action -> Attribute action
forall action. action -> Attribute action
E.onClick action
close
  ]
  [ [Attribute action] -> View model action
forall action model. [Attribute action] -> View model action
xIcon [] ]
-----------------------------------------------------------------------------
data Action
  = ShowDialog MisoString DOMRef
  | CloseDialog
  | NoOp
-----------------------------------------------------------------------------
-- | Demo component: two dialogs with triggers. The model tracks the id of
-- the currently open dialog.
dialogComponent :: Component parent props MisoString Action
dialogComponent :: forall parent props. Component parent props MisoString Action
dialogComponent = MisoString
-> (Action -> Effect parent props MisoString Action)
-> (props -> MisoString -> View MisoString Action)
-> Component parent props MisoString Action
forall model action parent props.
model
-> (action -> Effect parent props model action)
-> (props -> model -> View model action)
-> Component parent props model action
component MisoString
"" Action -> Effect parent props MisoString Action
forall {parent} {props} {action}.
Action
-> RWST
     (ComponentInfo parent props)
     [Schedule action]
     MisoString
     Identity
     ()
update_ ((props -> MisoString -> View MisoString Action)
 -> Component parent props MisoString Action)
-> (props -> MisoString -> View MisoString Action)
-> Component parent props MisoString Action
forall a b. (a -> b) -> a -> b
$ \props
_ MisoString
_ -> View MisoString Action
view_
  where
    update_ :: Action
-> RWST
     (ComponentInfo parent props)
     [Schedule action]
     MisoString
     Identity
     ()
update_ Action
NoOp = ()
-> RWST
     (ComponentInfo parent props)
     [Schedule action]
     MisoString
     Identity
     ()
forall a.
a
-> RWST
     (ComponentInfo parent props)
     [Schedule action]
     MisoString
     Identity
     a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
    update_ (ShowDialog MisoString
sel JSVal
domRef) = do
      Lens MisoString MisoString
forall a. Lens a a
this Lens MisoString MisoString
-> MisoString
-> RWST
     (ComponentInfo parent props)
     [Schedule action]
     MisoString
     Identity
     ()
forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> field -> m ()
.= MisoString
sel
      IO ()
-> RWST
     (ComponentInfo parent props)
     [Schedule action]
     MisoString
     Identity
     ()
forall parent props model action.
IO () -> Effect parent props model action
io_ (IO ()
 -> RWST
      (ComponentInfo parent props)
      [Schedule action]
      MisoString
      Identity
      ())
-> IO ()
-> RWST
     (ComponentInfo parent props)
     [Schedule action]
     MisoString
     Identity
     ()
forall a b. (a -> b) -> a -> b
$ do
        dialogRef <- JSVal -> IO JSVal
nextSibling JSVal
domRef
        void $ dialogRef # ("showModal" :: MisoString) $ ()

    update_ Action
CloseDialog = do
      sel <- Lens MisoString MisoString
-> RWST
     (ComponentInfo parent props)
     [Schedule action]
     MisoString
     Identity
     MisoString
forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> m field
use Lens MisoString MisoString
forall a. Lens a a
this
      io_ $ do
        dialog <- jsg "document"
          # ("getElementById" :: MisoString)
          $ [sel :: MisoString]
        void $ dialog # ("close" :: MisoString) $ ()
-----------------------------------------------------------------------------
view_ :: View MisoString Action
view_ :: View MisoString Action
view_ =
  [Attribute Action]
-> [View MisoString Action] -> View MisoString Action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.div_
  [ MisoString -> Attribute Action
forall action. MisoString -> Attribute action
P.class_ MisoString
"flex flex-wrap items-center gap-4" ]
  [ ButtonProps Action
-> [View MisoString Action] -> View MisoString Action
forall action model.
ButtonProps action -> [View model action] -> View model action
button_ ButtonProps (ZonkAny 0)
forall action. ButtonProps action
defaultButtonProps
    { buttonVariant = Outline
    , buttonAttrs = [ P.type_ "button", E.onClickWith (ShowDialog "demo-dialog-edit-profile") ]
    }
    [ View MisoString Action
"Edit Profile" ]
  , DialogProps Action
-> [View MisoString Action] -> View MisoString Action
forall action model.
DialogProps action -> [View model action] -> View model action
dialog_ DialogProps (ZonkAny 1)
forall action. DialogProps action
defaultDialogProps
    { dialogId = "demo-dialog-edit-profile"
    , dialogAttrs = [ E.onClick CloseDialog ]
    }
    [ [Attribute Action]
-> [View MisoString Action] -> View MisoString Action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.div_
      [ Options -> Action -> Attribute Action
forall action. Options -> action -> Attribute action
E.onClickWithOptions Options
stopPropagation Action
NoOp ]
      [ MisoString
-> [View MisoString Action]
-> [View MisoString Action]
-> View MisoString Action
forall model action.
MisoString
-> [View model action] -> [View model action] -> View model action
dialogHeader_ MisoString
"demo-dialog-edit-profile"
        [ View MisoString Action
"Edit profile" ]
        [ View MisoString Action
"Make changes to your profile here. Click save when you're done." ]
      , [Attribute Action]
-> [View MisoString Action] -> View MisoString Action
forall action model.
[Attribute action] -> [View model action] -> View model action
dialogSection_ []
        [ [Attribute Action]
-> [View MisoString Action] -> View MisoString Action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.form_
          [ MisoString -> Attribute Action
forall action. MisoString -> Attribute action
P.class_ MisoString
"form grid gap-4" ]
          [ [Attribute Action]
-> [View MisoString Action] -> View MisoString Action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.div_
            [ MisoString -> Attribute Action
forall action. MisoString -> Attribute action
P.class_ MisoString
"grid gap-3" ]
            [ LabelProps Action
-> [View MisoString Action] -> View MisoString Action
forall action model.
LabelProps action -> [View model action] -> View model action
label_ LabelProps Action
forall action. LabelProps action
defaultLabelProps { labelFor = Just "demo-dialog-edit-profile-name" }
              [ View MisoString Action
"Name" ]
            , InputProps Action -> View MisoString Action
forall action model. InputProps action -> View model action
input_ InputProps Action
forall action. InputProps action
defaultInputProps { inputId = Just "demo-dialog-edit-profile-name" }
            ]
          , [Attribute Action]
-> [View MisoString Action] -> View MisoString Action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.div_
            [ MisoString -> Attribute Action
forall action. MisoString -> Attribute action
P.class_ MisoString
"grid gap-3" ]
            [ LabelProps Action
-> [View MisoString Action] -> View MisoString Action
forall action model.
LabelProps action -> [View model action] -> View model action
label_ LabelProps Action
forall action. LabelProps action
defaultLabelProps { labelFor = Just "demo-dialog-edit-profile-username" }
              [ View MisoString Action
"Username" ]
            , InputProps Action -> View MisoString Action
forall action model. InputProps action -> View model action
input_ InputProps Action
forall action. InputProps action
defaultInputProps { inputId = Just "demo-dialog-edit-profile-username" }
            ]
          ]
        ]
      , [Attribute Action]
-> [View MisoString Action] -> View MisoString Action
forall action model.
[Attribute action] -> [View model action] -> View model action
dialogFooter_ []
        [ ButtonProps Action
-> [View MisoString Action] -> View MisoString Action
forall action model.
ButtonProps action -> [View model action] -> View model action
button_ ButtonProps (ZonkAny 2)
forall action. ButtonProps action
defaultButtonProps
          { buttonVariant = Outline, buttonAttrs = [ E.onClick CloseDialog ] }
          [ View MisoString Action
"Cancel" ]
        , ButtonProps Action
-> [View MisoString Action] -> View MisoString Action
forall action model.
ButtonProps action -> [View model action] -> View model action
button_ ButtonProps (ZonkAny 3)
forall action. ButtonProps action
defaultButtonProps
          { buttonAttrs = [ E.onClick CloseDialog ] }
          [ View MisoString Action
"Save changes" ]
        ]
      , Action -> View MisoString Action
forall action model. action -> View model action
dialogCloseButton_ Action
CloseDialog
      ]
    ]
  , ButtonProps Action
-> [View MisoString Action] -> View MisoString Action
forall action model.
ButtonProps action -> [View model action] -> View model action
button_ ButtonProps (ZonkAny 4)
forall action. ButtonProps action
defaultButtonProps
    { buttonVariant = Outline
    , buttonAttrs = [ P.type_ "button", E.onClickWith (ShowDialog "dialog-example") ]
    }
    [ View MisoString Action
"Scrollable Content" ]
  , DialogProps Action
-> [View MisoString Action] -> View MisoString Action
forall action model.
DialogProps action -> [View model action] -> View model action
dialog_ DialogProps (ZonkAny 5)
forall action. DialogProps action
defaultDialogProps
    { dialogId = "dialog-example"
    , dialogAttrs = [ E.onClick CloseDialog ]
    }
    [ [Attribute Action]
-> [View MisoString Action] -> View MisoString Action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.div_
      [ Options -> Action -> Attribute Action
forall action. Options -> action -> Attribute action
E.onClickWithOptions Options
stopPropagation Action
NoOp ]
      [ MisoString
-> [View MisoString Action]
-> [View MisoString Action]
-> View MisoString Action
forall model action.
MisoString
-> [View model action] -> [View model action] -> View model action
dialogHeader_ MisoString
"dialog-example"
        [ View MisoString Action
"Scrollable Content" ]
        [ View MisoString Action
"This is a dialog with scrollable content." ]
      , [Attribute Action]
-> [View MisoString Action] -> View MisoString Action
forall action model.
[Attribute action] -> [View model action] -> View model action
dialogSection_
        [ MisoString -> Attribute Action
forall action. MisoString -> Attribute action
P.class_ MisoString
"overflow-y-auto scrollbar" ]
        [ [Attribute Action]
-> [View MisoString Action] -> View MisoString Action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.div_
          [ MisoString -> Attribute Action
forall action. MisoString -> Attribute action
P.class_ MisoString
"space-y-4 text-sm" ]
          [ [Attribute Action]
-> [View MisoString Action] -> View MisoString Action
forall action model.
[Attribute action] -> [View model action] -> View model action
H.p_ [] [ View MisoString Action
lorem ] | Int
_ <- [ (Int
1 :: Int) .. Int
10 ] ]
        ]
      , [Attribute Action]
-> [View MisoString Action] -> View MisoString Action
forall action model.
[Attribute action] -> [View model action] -> View model action
dialogFooter_ []
        [ ButtonProps Action
-> [View MisoString Action] -> View MisoString Action
forall action model.
ButtonProps action -> [View model action] -> View model action
button_ ButtonProps (ZonkAny 6)
forall action. ButtonProps action
defaultButtonProps
          { buttonVariant = Outline, buttonAttrs = [ E.onClick CloseDialog ] }
          [ View MisoString Action
"Close" ]
        ]
      , Action -> View MisoString Action
forall action model. action -> View model action
dialogCloseButton_ Action
CloseDialog
      ]
    ]
  ]
  where
    lorem :: View MisoString Action
lorem =
      View MisoString Action
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
-----------------------------------------------------------------------------
dialogCodeSample :: View model action
dialogCodeSample :: forall model action. View model action
dialogCodeSample =
  View model action
"""
  -----------------------------------------------------------------------------
  module MyDialog (dialogComponent) where
  -----------------------------------------------------------------------------
  import           Control.Monad
  import           Miso
  import           Miso.Html.Event
  import           Miso.Lens
  import qualified Miso.Html as H
  import qualified Miso.Html.Property as P
  -----------------------------------------------------------------------------
  import           Miso.UI.Button
  import           Miso.UI.Dialog
  import           Miso.UI.Types
  -----------------------------------------------------------------------------
  data Action
    = ShowDialog MisoString DOMRef
    | CloseDialog
    | NoOp
  -----------------------------------------------------------------------------
  dialogComponent :: Component parent props MisoString Action
  dialogComponent = component "" update_ $ \\_ _ ->
      H.div_ []
      [ button_ defaultButtonProps
        { buttonVariant = Outline
        , buttonAttrs = [ onClickWith (ShowDialog "my-dialog") ]
        }
        [ "Edit Profile" ]
      , dialog_ defaultDialogProps
        { dialogId = "my-dialog"
        , dialogAttrs = [ onClick CloseDialog ]
        }
        [ H.div_
          [ onClickWithOptions stopPropagation NoOp ]
          [ dialogHeader_ "my-dialog"
            [ "Edit profile" ]
            [ "Make changes to your profile here." ]
          , dialogFooter_ []
            [ button_ defaultButtonProps
              { buttonAttrs = [ onClick CloseDialog ] }
              [ "Save changes" ]
            ]
          , dialogCloseButton_ CloseDialog
          ]
        ]
      ]
    where
      update_ NoOp = pure ()
      update_ (ShowDialog sel domRef) = do
        this .= sel
        io_ $ do
          dialogRef <- nextSibling domRef
          void $ dialogRef # ("showModal" :: MisoString) $ ()
      update_ CloseDialog = do
        sel <- use this
        io_ $ do
          dialog <- jsg "document"
            # ("getElementById" :: MisoString)
            $ [sel :: MisoString]
          void $ dialog # ("close" :: MisoString) $ ()
  """
-----------------------------------------------------------------------------
dialogPropsApi :: View model action
dialogPropsApi :: forall model action. View model action
dialogPropsApi =
  View model action
"""
  -- | Props for 'dialog_' (the native @dialog@ element)
  data DialogProps action
    = DialogProps
    { dialogId :: MisoString
      -- ^ id of the dialog; @-title@ \\/ @-description@ ids derive from it
    , dialogClasses :: [MisoString]
      -- ^ Extra classes appended to @dialog.dialog@
    , dialogAttrs :: [Attribute action]
    }
  -----------------------------------------------------------------------------
  -- | Smart constructor
  defaultDialogProps :: DialogProps action
  defaultDialogProps
    = DialogProps
    { dialogId = "dialog"
    , dialogClasses = [ "w-full", "sm:max-w-[425px]", "max-h-[612px]" ]
    , dialogAttrs = []
    }
  """
-----------------------------------------------------------------------------