packages feed

miso-css-0.0.3: src/Miso/Css/Style/E.hs

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE UndecidableInstances #-}

module Miso.Css.Style.E where


import Data.String ( IsString(..) )
import Data.Type.Bool ( If )
import GHC.TypeLits (Natural, KnownNat, AppendSymbol, KnownChar)
import Miso ( MisoString, ms, View )
import Miso.Css.Event (EventFactory)
import Miso.Css.List ( MergeUniq, Elem, PrependMb, Append, Diff, FilterOut
                     , MergeDedup, FindDuplicates, CatMaybes )
import Miso.Css.Prelude
import Miso.Css.Segment
    ( ApplyClass,
      ApplySubSegsToElem,
      BRANCH,
      MbSymToMbI,
      SubSeg(C, R, I, T, A) )

import Miso.Css.Style.OrClass ( OrClass )
import Miso.Css.Style.PostAppend qualified as Post
import Miso.Css.Style.PreAppend qualified as Pre
import Miso.JSON ( ToJSON )

data ElementId (ei :: Symbol)
data TabIdx (ei :: Natural)

newtype ElAtr k v = ElAtr v deriving newtype (Eq, Ord, Show, ToJSON) deriving (Generic)

elAtrKey :: forall k v. KnownSymbol k => ElAtr k v -> MisoString
elAtrKey _ = ms $ symbolVal (Proxy @k)

elAtrVal :: forall {k1} {k2 :: k1} {v}. ElAtr k2 v -> v
elAtrVal (ElAtr v) = v

type family AppendChild children ceacs pcls peacs where
  AppendChild children ceacs '[] peacs =
    (Append (Post.MapMaybeFilterOutFullyMatchedHead children ceacs) peacs)
  AppendChild children ceacs (pclsH : pcls') peacs =
    AppendChild children (ApplyClass '[] pclsH ceacs) pcls' peacs

type family SymsToSubSeg l where
  SymsToSubSeg '[] = '[]
  SymsToSubSeg (h : l) = C h : SymsToSubSeg l

type family SymsToAtrs l where
  SymsToAtrs '[] = '[]
  SymsToAtrs (h : l) = A h : SymsToAtrs l

data ElementStructure = Atomic | Composite

newtype DuplicatedID = DuplicatedId Symbol

data KnownIDS = KnownIds { duplicatedIds :: [DuplicatedID], knownIds :: [Symbol] }

type family DuplicatedIds kids where
  DuplicatedIds (KnownIds dids _) = dids

type family AddTagId x kids where
  AddTagId x (KnownIds dids kids) =
    If (Elem x kids)
      (KnownIds (DuplicatedId x : dids) kids)
      (KnownIds dids (x : kids))

type family AddForId fi for kids where
  AddForId fi for (KnownIds _dids kids) =
    If (Elem fi kids)
       for
       (If (Elem fi for)
           for
           (fi : for))

type family MergeFors pkids ckids pfors cfors where
  MergeFors (KnownIds _ pkids) (KnownIds _ ckids) pfors cfors =
    (Diff (Diff (MergeDedup pfors cfors '[]) pkids) ckids)

type family MergeKidsCase r didsA didsB kidsA kidsB where
  MergeKidsCase (Left e) didsA didsB kidsA kidsB =
    KnownIds
      (DuplicatedId e : Append didsA didsB)
      (Append kidsA kidsB)
  MergeKidsCase (Right kidsAB) didsA didsB _kidsA _kidsB =
    KnownIds
      (Append didsA didsB)
      kidsAB

type family MergeKids a b where
  MergeKids (KnownIds didsA kidsA) (KnownIds didsB kidsB) =
    MergeKidsCase (MergeUniq kidsA kidsB '[]) didsA didsB kidsA kidsB

type family TabIndexesConsistent tis where
 TabIndexesConsistent tis = FindDuplicates (FilterOut 0 (CatMaybes tis))
type family AccessKeyConsistent aks where
  AccessKeyConsistent aks = FindDuplicates aks

type EmptyKids = KnownIds '[] '[]

type CD = "CDATA"
type RMV = "RawMisoView"
type HTML = "html"
type BODY = "body"
data Root = Root deriving (Show, Eq)

type ConstraintsAfterAppend ::
  [[SubSeg]] -> [[BRANCH]] ->
  Maybe Symbol -> Symbol -> [Symbol] -> [Symbol] ->
  [[BRANCH]] -> [[BRANCH]]
type family ConstraintsAfterAppend pchildren ceacs pi pe pAtrs pcls peacs where
  ConstraintsAfterAppend pchildren ceacs pi pe pAtrs pcls peacs =
    AppendChild
      pchildren
      (Pre.MapMaybeFilterOutFullyMatchedHead '[] ceacs)
      (PrependMb
        (MbSymToMbI pi)
        (T pe : Append (SymsToAtrs pAtrs) (SymsToSubSeg pcls)))
      peacs

type family ChildrenConstrAfterAppend ci ce ccls pchildren where
  ChildrenConstrAfterAppend ci ce ccls pchildren =
    PrependMb (MbSymToMbI ci) (T ce : SymsToSubSeg ccls) : pchildren

type family ConstraintsAfterClassApp ei en atrs cls p c eacs where
  ConstraintsAfterClassApp ei en atrs cls p c eacs =
    ApplyClass
      (ApplySubSegsToElem
        (PrependMb
          (MbSymToMbI ei)
          (T en : A "class" : Append (SymsToAtrs atrs) (SymsToSubSeg cls)))
        p)
      (C c)
      eacs

type family ConstraintsAfteId ei eacs where
  ConstraintsAfteId ei eacs = ApplyClass '[] (A "id") (ApplyClass '[] (I ei) eacs)

type family AttributeIsReserved a f where
  AttributeIsReserved a f =
    "Tag attribue [" `AppendSymbol` a `AppendSymbol` "] is reserved - use ("
      `AppendSymbol` f `AppendSymbol` ") function for it"

type family RegularAtr a where
  RegularAtr "id" = AttributeIsReserved "id" "=#"
  RegularAtr "for" = AttributeIsReserved "for" "`for`"
  RegularAtr "tabindex" =
    AttributeIsReserved "tabindex" "`tabIndex`"
  RegularAtr "aria-labelledby" =
    AttributeIsReserved "aria-labelledby" "`ariaLabelledBy`"
  RegularAtr "aria-discribedby" =
    AttributeIsReserved "aria-discribedby" "`ariaDiscribedBy`"
  RegularAtr a = ""

data E
     ctx props model action
     (en :: Symbol)
     (es :: ElementStructure)
     (re :: Maybe Root)
     (ei :: Maybe Symbol)
     (atrs :: [Symbol])
     (knownIds :: KnownIDS)
     (cls :: [Symbol])
     (l :: [[BRANCH]])
     (children :: [[SubSeg]])
     (wantedIds :: [Symbol])
     (usedTabIndexes :: [Maybe Natural])
     (usedAccessKey :: [Char])
  where
    RawMisoView ::
      View ctx props model action ->
      E ctx props model action RMV Atomic Nothing Nothing '[] EmptyKids '[] '[] '[] '[] '[] '[]
    CDataE ::
      MisoString ->
      E ctx props model action CD Atomic Nothing Nothing '[] EmptyKids '[] '[] '[] '[] '[] '[]
    NilE :: KnownSymbol en =>
      Proxy en ->
      E ctx props model action en Composite Nothing Nothing '[] EmptyKids '[] '[] '[] '[] '[] '[]
    AddAtrE :: (KnownSymbol k, ToJSON v, RegularAtr k ~ "") =>
      ElAtr k v ->
      E ctx props model action en Composite r ei atrs kids cls eacs children for tabx ak ->
      E ctx props model action en Composite r ei (k : atrs) kids cls
        (ApplyClass '[] (A k) eacs)
        children
        for tabx ak
    AddAriaIdAtrE :: (KnownSymbol a, KnownSymbol fi) =>
      Proxy a ->
      Proxy fi ->
      E ctx props model action en Composite r ei atrs kids cls eacs children for tabx ak ->
      E ctx props model action en Composite r ei atrs kids cls eacs children
      (AddForId fi for kids) tabx ak
    AddForAtrE :: KnownSymbol fi =>
      Proxy fi ->
      E ctx props model action en Composite r ei atrs kids cls eacs children for tabx ak ->
      E ctx props model action en Composite r ei atrs kids cls eacs children
      (AddForId fi for kids) tabx ak
    AccessKeyE :: KnownChar nc =>
      Proxy nc ->
      E ctx props model action en Composite r ei atrs kids cls eacs children for tabx ak ->
      E ctx props model action en Composite r ei atrs kids cls eacs children for tabx (nc : ak)
    TabIndexE :: KnownNat ti =>
      Proxy ti ->
      E ctx props model action en Composite r ei atrs kids cls eacs children for tabx ak ->
      E ctx props model action en Composite r ei atrs kids cls eacs children for (Just ti : tabx) ak
    TabIndexMinus1E ::
      E ctx props model action en Composite r ei atrs kids cls eacs children for tabx ak ->
      E ctx props model action en Composite r ei atrs kids cls eacs children for (Nothing : tabx) ak
    IdE :: KnownSymbol ei =>
      Proxy ei ->
      E ctx props model action en Composite r Nothing atrs kids cls eacs children for tabx ak ->
      E ctx props model action en Composite r (Just ei) ("id" : atrs)
        (AddTagId ei kids)
        cls
        (ConstraintsAfteId ei eacs)
        children
        (FilterOut ei for)
        tabx ak
    BindEventE :: EventFactory ef model action =>
      ef ->
      E ctx props model action en es r ei atrs kids cls eacs children for tabx ak ->
      E ctx props model action en es r ei atrs kids cls eacs children for tabx ak
    AppClsE :: (KnownSymbol en, KnownSymbol c) =>
      OrClass p c ->
      E ctx props model action en Composite r ei atrs kIds cls eacs children for tabx ak ->
      E ctx props model action en Composite r ei ("class" : atrs) kIds (c : cls)
        (ConstraintsAfterClassApp ei en atrs cls p c eacs)
        children for tabx ak
    AppendChildE :: KnownSymbol ce =>
      E ctx props model action ce cs Nothing ci cAtrs ckIds ccls ceacs cchildren cfor ctabx cak ->
      E ctx props model action pe Composite r pi pAtrs pkIds pcls peacs pchildren pfor ptabx pak ->
      E ctx props model action pe Composite r pi pAtrs
      (MergeKids ckIds pkIds)
      pcls
      (ConstraintsAfterAppend pchildren ceacs pi pe pAtrs pcls peacs)
      (ChildrenConstrAfterAppend ci ce ccls pchildren)
      (MergeFors pkIds ckIds pfor cfor)
      (Append ptabx ctabx)
      (Append pak cak)
    -- Miso can render view up to body to support :root the library provide
    -- VirtualBodyE and SealDomE to emulate top DOM elements (body and html) without
    -- generating them because the already exist
    VirtualBodyE ::
      E ctx props model action ce cs Nothing ci catrs ckids ccls ceacs cchildren for tabx ak ->
      E ctx props model action BODY Composite Nothing Nothing catrs
        ckids
        '[]
        (AppendChild
          '[]  -- pchildren
          ceacs
          '[ T BODY ]
          '[])
        '[ PrependMb (MbSymToMbI ci) (T ce : SymsToSubSeg ccls) ]
        for tabx ak
    SealDomE ::
      E ctx props model action
          ce   cs        Nothing      ci      catrs ckids ccls ceacs cchildren for tabx ak ->
      E ctx props model action
          HTML Composite (Just 'Root) Nothing catrs ckids '[]
        (Post.MapMaybeFilterOutFullyMatchedHead
          '[]
          (ApplyClass '[] (T HTML) (ApplyClass '[] R ceacs)))
        '[ PrependMb (MbSymToMbI ci) (T ce : SymsToSubSeg ccls) ]
        for tabx ak

instance IsString (E ctx props model action CD Atomic Nothing Nothing '[] EmptyKids
                   '[] '[] '[] '[] '[] '[]) where
  fromString = CDataE . ms