miso 1.8.7.0 → 1.9.0.0
raw patch · 100 files changed
+24184/−6219 lines, 100 filesdep +ghc-experimentaldep +ghcjs-primdep +mtldep −QuickCheckdep −aesondep −file-embeddep ~bytestringdep ~containersdep ~textPVP ok
version bump matches the API change (PVP)
Dependencies added: ghc-experimental, ghcjs-prim, mtl, template-haskell
Dependencies removed: QuickCheck, aeson, file-embed, http-api-data, http-types, jsaddle, lucid, miso, network-uri, quickcheck-instances, scientific, servant, servant-lucid, tagsoup, unordered-containers, vector
Dependency ranges changed: bytestring, containers, text, transformers
API changes (from Hackage documentation)
- Miso: sink :: Sink action
- Miso.Delegate: delegator :: JSVal -> IORef VTree -> Map MisoString Bool -> JSM ()
- Miso.Dev: clearBody :: JSM ()
- Miso.Diff: diff :: Maybe MisoString -> Maybe VTree -> Maybe VTree -> JSM ()
- Miso.Diff: mountElement :: Maybe MisoString -> JSM JSVal
- Miso.Effect: Effect :: model -> [Sub action] -> Effect action model
- Miso.Effect: batchEff :: model -> [JSM action] -> Effect action model
- Miso.Effect: data Effect action model
- Miso.Effect: effectSub :: model -> Sub action -> Effect action model
- Miso.Effect: instance Data.Bifunctor.Bifunctor Miso.Effect.Effect
- Miso.Effect: instance GHC.Base.Applicative (Miso.Effect.Effect action)
- Miso.Effect: instance GHC.Base.Functor (Miso.Effect.Effect action)
- Miso.Effect: instance GHC.Base.Monad (Miso.Effect.Effect action)
- Miso.Effect: noEff :: model -> Effect action model
- Miso.Effect.DOM: alert :: MisoString -> JSM ()
- Miso.Effect.DOM: blur :: MisoString -> JSM ()
- Miso.Effect.DOM: focus :: MisoString -> JSM ()
- Miso.Effect.DOM: scrollIntoView :: MisoString -> JSM ()
- Miso.Effect.Storage: clearLocalStorage :: JSM ()
- Miso.Effect.Storage: clearSessionStorage :: JSM ()
- Miso.Effect.Storage: getLocalStorage :: FromJSON model => MisoString -> JSM (Either String model)
- Miso.Effect.Storage: getSessionStorage :: FromJSON model => MisoString -> JSM (Either String model)
- Miso.Effect.Storage: localStorageLength :: JSM Int
- Miso.Effect.Storage: removeLocalStorage :: MisoString -> JSM ()
- Miso.Effect.Storage: removeSessionStorage :: MisoString -> JSM ()
- Miso.Effect.Storage: sessionStorageLength :: JSM Int
- Miso.Effect.Storage: setLocalStorage :: ToJSON model => MisoString -> model -> JSM ()
- Miso.Effect.Storage: setSessionStorage :: ToJSON model => MisoString -> model -> JSM ()
- Miso.Event.Decoder: instance GHCJS.Marshal.Internal.ToJSVal Miso.Event.Decoder.DecodeTarget
- Miso.Event.Types: AllowDrop :: Bool -> AllowDrop
- Miso.Event.Types: [preventDefault] :: Options -> Bool
- Miso.Event.Types: [shiftKey, metaKey, ctrlKey, altKey] :: KeyInfo -> !Bool
- Miso.Event.Types: [stopPropagation] :: Options -> Bool
- Miso.Event.Types: instance Data.Aeson.Types.FromJSON.FromJSON Miso.Event.Types.AllowDrop
- Miso.Event.Types: instance Data.Aeson.Types.FromJSON.FromJSON Miso.Event.Types.Checked
- Miso.Event.Types: instance Data.Aeson.Types.FromJSON.FromJSON Miso.Event.Types.KeyCode
- Miso.Event.Types: instance GHC.Classes.Eq Miso.Event.Types.AllowDrop
- Miso.Event.Types: instance GHC.Generics.Generic Miso.Event.Types.Options
- Miso.Event.Types: instance GHC.Show.Show Miso.Event.Types.AllowDrop
- Miso.Event.Types: instance GHCJS.Marshal.Internal.ToJSVal Miso.Event.Types.Options
- Miso.Event.Types: newtype AllowDrop
- Miso.FFI: callbackToJSVal :: Function -> JSM JSVal
- Miso.FFI: clearBody :: JSM ()
- Miso.FFI: consoleLogJSVal :: JSVal -> JSM ()
- Miso.FFI: copyDOMIntoVTree :: Bool -> JSVal -> JSVal -> JSM ()
- Miso.FFI: data () => JSM a
- Miso.FFI: delegateEvent :: JSVal -> JSVal -> JSM JSVal -> JSM ()
- Miso.FFI: diff' :: Object -> Object -> JSVal -> JSVal -> JSM ()
- Miso.FFI: forkJSM :: JSM () -> JSM ()
- Miso.FFI: getBody :: JSM JSVal
- Miso.FFI: getDoc :: JSM JSVal
- Miso.FFI: ghcjsPure :: GHCJSPure a -> JSM a
- Miso.FFI: integralToJSString :: Integral a => a -> MisoString
- Miso.FFI: jsStringToDouble :: MisoString -> Double
- Miso.FFI: objectToJSON :: JSVal -> JSVal -> JSM JSVal
- Miso.FFI: objectToJSVal :: Object -> JSM JSVal
- Miso.FFI: parse :: FromJSON json => JSVal -> JSM json
- Miso.FFI: realFloatToJSString :: RealFloat a => a -> MisoString
- Miso.FFI: registerCallback :: JSVal -> JSM ()
- Miso.FFI: releaseCallbacks :: JSM ()
- Miso.FFI: stringify :: ToJSON json => json -> JSM MisoString
- Miso.FFI: swapCallbacks :: JSM ()
- Miso.FFI: syncPoint :: JSM ()
- Miso.FFI: windowAddEventListener :: MisoString -> (JSVal -> JSM ()) -> JSM ()
- Miso.FFI.History: back :: JSM ()
- Miso.FFI.History: forward :: JSM ()
- Miso.FFI.History: getWindowLocationHref :: JSM MisoString
- Miso.FFI.History: go :: Int -> JSM ()
- Miso.FFI.History: pushState :: MisoString -> JSM ()
- Miso.FFI.History: replaceState :: MisoString -> JSM ()
- Miso.FFI.SSE: EventSource :: JSVal -> EventSource
- Miso.FFI.SSE: addEventListener :: EventSource -> MisoString -> (JSVal -> JSM ()) -> JSM ()
- Miso.FFI.SSE: data' :: JSVal -> JSM JSVal
- Miso.FFI.SSE: new :: MisoString -> JSM EventSource
- Miso.FFI.SSE: newtype EventSource
- Miso.FFI.Storage: clear :: Storage -> JSM ()
- Miso.FFI.Storage: data Storage
- Miso.FFI.Storage: getItem :: Storage -> MisoString -> JSM JSVal
- Miso.FFI.Storage: length :: Storage -> JSM Int
- Miso.FFI.Storage: localStorage :: JSM Storage
- Miso.FFI.Storage: removeItem :: Storage -> MisoString -> JSM ()
- Miso.FFI.Storage: sessionStorage :: JSM Storage
- Miso.FFI.Storage: setItem :: Storage -> MisoString -> MisoString -> JSM ()
- Miso.FFI.WebSocket: Socket :: JSVal -> Socket
- Miso.FFI.WebSocket: addEventListener :: Socket -> MisoString -> (JSVal -> JSM ()) -> JSM ()
- Miso.FFI.WebSocket: close :: Socket -> JSM ()
- Miso.FFI.WebSocket: code :: JSVal -> JSM Int
- Miso.FFI.WebSocket: create :: MisoString -> JSVal -> JSM Socket
- Miso.FFI.WebSocket: data' :: JSVal -> JSM JSVal
- Miso.FFI.WebSocket: newtype Socket
- Miso.FFI.WebSocket: reason :: JSVal -> JSM Reason
- Miso.FFI.WebSocket: send :: Socket -> MisoString -> JSM ()
- Miso.FFI.WebSocket: socketState :: Socket -> JSM Int
- Miso.FFI.WebSocket: wasClean :: JSVal -> JSM WasClean
- Miso.Html: E :: (Sink action -> Object -> JSM ()) -> Attribute action
- Miso.Html: HTML :: NS
- Miso.Html: Key :: MisoString -> Key
- Miso.Html: MATHML :: NS
- Miso.Html: Node :: NS -> MisoString -> Maybe Key -> [Attribute action] -> [View action] -> View action
- Miso.Html: P :: MisoString -> Value -> Attribute action
- Miso.Html: S :: Map MisoString MisoString -> Attribute action
- Miso.Html: SVG :: NS
- Miso.Html: Text :: MisoString -> View action
- Miso.Html: TextRaw :: MisoString -> View action
- Miso.Html: VTree :: Object -> VTree
- Miso.Html: [getTree] :: VTree -> Object
- Miso.Html: a_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: abbr_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: acceptCharset_ :: MisoString -> Attribute action
- Miso.Html: accept_ :: MisoString -> Attribute action
- Miso.Html: action_ :: MisoString -> Attribute action
- Miso.Html: address_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: align_ :: MisoString -> Attribute action
- Miso.Html: alt_ :: MisoString -> Attribute action
- Miso.Html: article_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: aside_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: async_ :: MisoString -> Attribute action
- Miso.Html: audio_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: autocomplete_ :: Bool -> Attribute action
- Miso.Html: autofocus_ :: Bool -> Attribute action
- Miso.Html: autoplay_ :: Bool -> Attribute action
- Miso.Html: autosave_ :: MisoString -> Attribute action
- Miso.Html: b_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: bdi_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: bdo_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: blockquote_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: body_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: boolProp :: MisoString -> Bool -> Attribute action
- Miso.Html: br_ :: [Attribute action] -> View action
- Miso.Html: button_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: canvas_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: caption_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: center_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: charset_ :: MisoString -> Attribute action
- Miso.Html: checked_ :: Bool -> Attribute action
- Miso.Html: cite_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: class ToKey key
- Miso.Html: class ToView v
- Miso.Html: classList_ :: [(MisoString, Bool)] -> Attribute action
- Miso.Html: class_ :: MisoString -> Attribute action
- Miso.Html: code_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: col_ :: [Attribute action] -> View action
- Miso.Html: colgroup_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: cols_ :: MisoString -> Attribute action
- Miso.Html: colspan_ :: MisoString -> Attribute action
- Miso.Html: content_ :: MisoString -> Attribute action
- Miso.Html: controls_ :: Bool -> Attribute action
- Miso.Html: coords_ :: MisoString -> Attribute action
- Miso.Html: data Attribute action
- Miso.Html: data NS
- Miso.Html: data View action
- Miso.Html: data_ :: MisoString -> MisoString -> Attribute action
- Miso.Html: datalist_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: dd_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: defaultValue_ :: MisoString -> Attribute action
- Miso.Html: default_ :: Bool -> Attribute action
- Miso.Html: defer_ :: MisoString -> Attribute action
- Miso.Html: del_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: details_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: dfn_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: disabled_ :: Bool -> Attribute action
- Miso.Html: div_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: dl_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: doubleProp :: MisoString -> Double -> Attribute action
- Miso.Html: downloadAs_ :: MisoString -> Attribute action
- Miso.Html: download_ :: MisoString -> Attribute action
- Miso.Html: dt_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: em_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: embed_ :: [Attribute action] -> View action
- Miso.Html: enctype_ :: MisoString -> Attribute action
- Miso.Html: fieldset_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: figcaption_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: figure_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: footer_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: for_ :: MisoString -> Attribute action
- Miso.Html: form_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: formation_ :: MisoString -> Attribute action
- Miso.Html: h1_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: h2_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: h3_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: h4_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: h5_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: h6_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: header_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: headers_ :: MisoString -> Attribute action
- Miso.Html: height_ :: MisoString -> Attribute action
- Miso.Html: hidden_ :: Bool -> Attribute action
- Miso.Html: hr_ :: [Attribute action] -> View action
- Miso.Html: href_ :: MisoString -> Attribute action
- Miso.Html: hreflang_ :: MisoString -> Attribute action
- Miso.Html: httpEquiv_ :: MisoString -> Attribute action
- Miso.Html: i_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: id_ :: MisoString -> Attribute action
- Miso.Html: iframe_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: img_ :: [Attribute action] -> View action
- Miso.Html: input_ :: [Attribute action] -> View action
- Miso.Html: ins_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: intProp :: MisoString -> Int -> Attribute action
- Miso.Html: integerProp :: MisoString -> Int -> Attribute action
- Miso.Html: ismap_ :: MisoString -> Attribute action
- Miso.Html: kbd_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: keygen_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: kind_ :: MisoString -> Attribute action
- Miso.Html: label_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: language_ :: MisoString -> Attribute action
- Miso.Html: legend_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: liKeyed_ :: Key -> [Attribute action] -> [View action] -> View action
- Miso.Html: li_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: link_ :: [Attribute action] -> View action
- Miso.Html: list_ :: MisoString -> Attribute action
- Miso.Html: loading_ :: MisoString -> Attribute action
- Miso.Html: loop_ :: Bool -> Attribute action
- Miso.Html: main_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: mark_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: math_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: max_ :: MisoString -> Attribute action
- Miso.Html: maxlength_ :: MisoString -> Attribute action
- Miso.Html: media_ :: MisoString -> Attribute action
- Miso.Html: menu_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: menuitem_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: meter_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: method_ :: MisoString -> Attribute action
- Miso.Html: min_ :: MisoString -> Attribute action
- Miso.Html: minlength_ :: MisoString -> Attribute action
- Miso.Html: multiple_ :: Bool -> Attribute action
- Miso.Html: name_ :: MisoString -> Attribute action
- Miso.Html: nav_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: newtype Key
- Miso.Html: newtype VTree
- Miso.Html: node :: NS -> MisoString -> Maybe Key -> [Attribute action] -> [View action] -> View action
- Miso.Html: nodeHtml :: MisoString -> [Attribute action] -> [View action] -> View action
- Miso.Html: nodeHtmlKeyed :: MisoString -> Key -> [Attribute action] -> [View action] -> View action
- Miso.Html: novalidate_ :: Bool -> Attribute action
- Miso.Html: object_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: ol_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: on :: MisoString -> Decoder r -> (r -> action) -> Attribute action
- Miso.Html: onBeforeDestroyed :: action -> Attribute action
- Miso.Html: onCreated :: action -> Attribute action
- Miso.Html: onDestroyed :: action -> Attribute action
- Miso.Html: onWithOptions :: Options -> MisoString -> Decoder r -> (r -> action) -> Attribute action
- Miso.Html: optgroup_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: option_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: output_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: p_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: param_ :: [Attribute action] -> View action
- Miso.Html: pattern_ :: MisoString -> Attribute action
- Miso.Html: ping_ :: MisoString -> Attribute action
- Miso.Html: placeholder_ :: MisoString -> Attribute action
- Miso.Html: poster_ :: MisoString -> Attribute action
- Miso.Html: pre_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: preload_ :: MisoString -> Attribute action
- Miso.Html: progress_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: prop :: ToJSON a => MisoString -> a -> Attribute action
- Miso.Html: q_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: rawHtml :: MisoString -> View action
- Miso.Html: readonly_ :: Bool -> Attribute action
- Miso.Html: ref_ :: MisoString -> Attribute action
- Miso.Html: rel_ :: MisoString -> Attribute action
- Miso.Html: required_ :: Bool -> Attribute action
- Miso.Html: reversed_ :: MisoString -> Attribute action
- Miso.Html: rows_ :: MisoString -> Attribute action
- Miso.Html: rowspan_ :: MisoString -> Attribute action
- Miso.Html: rp_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: rt_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: ruby_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: runView :: View action -> Sink action -> JSM VTree
- Miso.Html: s_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: samp_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: sandbox_ :: MisoString -> Attribute action
- Miso.Html: scope_ :: MisoString -> Attribute action
- Miso.Html: scoped_ :: MisoString -> Attribute action
- Miso.Html: script_ :: [Attribute action] -> MisoString -> View action
- Miso.Html: seamless_ :: MisoString -> Attribute action
- Miso.Html: section_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: select_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: selected_ :: Bool -> Attribute action
- Miso.Html: shape_ :: MisoString -> Attribute action
- Miso.Html: size_ :: MisoString -> Attribute action
- Miso.Html: small_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: source_ :: [Attribute action] -> View action
- Miso.Html: span_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: src_ :: MisoString -> Attribute action
- Miso.Html: srcdoc_ :: MisoString -> Attribute action
- Miso.Html: srclang_ :: MisoString -> Attribute action
- Miso.Html: start_ :: MisoString -> Attribute action
- Miso.Html: step_ :: MisoString -> Attribute action
- Miso.Html: stringProp :: MisoString -> String -> Attribute action
- Miso.Html: strong_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: styleInline_ :: MisoString -> Attribute action
- Miso.Html: style_ :: Map MisoString MisoString -> Attribute action
- Miso.Html: sub_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: summary_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: sup_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: table_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: target_ :: MisoString -> Attribute action
- Miso.Html: tbody_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: td_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: text :: MisoString -> View action
- Miso.Html: textProp :: MisoString -> MisoString -> Attribute action
- Miso.Html: textarea_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: tfoot_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: th_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: thead_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: time_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: title_ :: MisoString -> Attribute action
- Miso.Html: toKey :: ToKey key => key -> Key
- Miso.Html: toView :: ToView v => v -> View action
- Miso.Html: trKeyed_ :: Key -> [Attribute action] -> [View action] -> View action
- Miso.Html: tr_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: track_ :: [Attribute action] -> View action
- Miso.Html: type_ :: MisoString -> Attribute action
- Miso.Html: u_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: ul_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: usemap_ :: MisoString -> Attribute action
- Miso.Html: value_ :: MisoString -> Attribute action
- Miso.Html: var_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: video_ :: [Attribute action] -> [View action] -> View action
- Miso.Html: wbr_ :: [Attribute action] -> View action
- Miso.Html: width_ :: MisoString -> Attribute action
- Miso.Html: wrap_ :: MisoString -> Attribute action
- Miso.Html.Element: center_ :: [Attribute action] -> [View action] -> View action
- Miso.Html.Element: keygen_ :: [Attribute action] -> [View action] -> View action
- Miso.Html.Element: liKeyed_ :: Key -> [Attribute action] -> [View action] -> View action
- Miso.Html.Element: math_ :: [Attribute action] -> [View action] -> View action
- Miso.Html.Element: menuitem_ :: [Attribute action] -> [View action] -> View action
- Miso.Html.Element: nodeHtmlKeyed :: MisoString -> Key -> [Attribute action] -> [View action] -> View action
- Miso.Html.Element: param_ :: [Attribute action] -> View action
- Miso.Html.Element: trKeyed_ :: Key -> [Attribute action] -> [View action] -> View action
- Miso.Html.Event: Options :: Bool -> Bool -> Options
- Miso.Html.Event: [preventDefault] :: Options -> Bool
- Miso.Html.Event: [stopPropagation] :: Options -> Bool
- Miso.Html.Event: data Options
- Miso.Html.Event: defaultOptions :: Options
- Miso.Html.Event: on :: MisoString -> Decoder r -> (r -> action) -> Attribute action
- Miso.Html.Event: onWithOptions :: Options -> MisoString -> Decoder r -> (r -> action) -> Attribute action
- Miso.Html.Property: boolProp :: MisoString -> Bool -> Attribute action
- Miso.Html.Property: doubleProp :: MisoString -> Double -> Attribute action
- Miso.Html.Property: intProp :: MisoString -> Int -> Attribute action
- Miso.Html.Property: integerProp :: MisoString -> Int -> Attribute action
- Miso.Html.Property: novalidate_ :: Bool -> Attribute action
- Miso.Html.Property: start_ :: MisoString -> Attribute action
- Miso.Html.Property: stringProp :: MisoString -> String -> Attribute action
- Miso.Html.Property: styleInline_ :: MisoString -> Attribute action
- Miso.Html.Property: textProp :: MisoString -> MisoString -> Attribute action
- Miso.Html.Types: E :: (Sink action -> Object -> JSM ()) -> Attribute action
- Miso.Html.Types: HTML :: NS
- Miso.Html.Types: Key :: MisoString -> Key
- Miso.Html.Types: MATHML :: NS
- Miso.Html.Types: Node :: NS -> MisoString -> Maybe Key -> [Attribute action] -> [View action] -> View action
- Miso.Html.Types: P :: MisoString -> Value -> Attribute action
- Miso.Html.Types: S :: Map MisoString MisoString -> Attribute action
- Miso.Html.Types: SVG :: NS
- Miso.Html.Types: Text :: MisoString -> View action
- Miso.Html.Types: TextRaw :: MisoString -> View action
- Miso.Html.Types: VTree :: Object -> VTree
- Miso.Html.Types: [getTree] :: VTree -> Object
- Miso.Html.Types: class ToKey key
- Miso.Html.Types: class ToView v
- Miso.Html.Types: data Attribute action
- Miso.Html.Types: data NS
- Miso.Html.Types: data View action
- Miso.Html.Types: instance Data.String.IsString (Miso.Html.Types.View a)
- Miso.Html.Types: instance GHC.Base.Functor Miso.Html.Types.Attribute
- Miso.Html.Types: instance GHC.Base.Functor Miso.Html.Types.View
- Miso.Html.Types: instance GHC.Classes.Eq Miso.Html.Types.NS
- Miso.Html.Types: instance GHC.Show.Show Miso.Html.Types.NS
- Miso.Html.Types: instance GHCJS.Marshal.Internal.ToJSVal Miso.Html.Types.Key
- Miso.Html.Types: instance GHCJS.Marshal.Internal.ToJSVal Miso.Html.Types.NS
- Miso.Html.Types: instance Lucid.Base.ToHtml (Miso.Html.Types.View action)
- Miso.Html.Types: instance Miso.Html.Types.ToKey Data.JSString.Internal.Type.JSString
- Miso.Html.Types: instance Miso.Html.Types.ToKey Data.Text.Internal.Text
- Miso.Html.Types: instance Miso.Html.Types.ToKey GHC.Base.String
- Miso.Html.Types: instance Miso.Html.Types.ToKey GHC.Types.Double
- Miso.Html.Types: instance Miso.Html.Types.ToKey GHC.Types.Float
- Miso.Html.Types: instance Miso.Html.Types.ToKey GHC.Types.Int
- Miso.Html.Types: instance Miso.Html.Types.ToKey GHC.Types.Word
- Miso.Html.Types: instance Miso.Html.Types.ToKey Miso.Html.Types.Key
- Miso.Html.Types: instance Servant.Links.HasLink (Miso.Html.Types.View a)
- Miso.Html.Types: newtype Key
- Miso.Html.Types: newtype VTree
- Miso.Html.Types: node :: NS -> MisoString -> Maybe Key -> [Attribute action] -> [View action] -> View action
- Miso.Html.Types: on :: MisoString -> Decoder r -> (r -> action) -> Attribute action
- Miso.Html.Types: onBeforeDestroyed :: action -> Attribute action
- Miso.Html.Types: onCreated :: action -> Attribute action
- Miso.Html.Types: onDestroyed :: action -> Attribute action
- Miso.Html.Types: onWithOptions :: Options -> MisoString -> Decoder r -> (r -> action) -> Attribute action
- Miso.Html.Types: prop :: ToJSON a => MisoString -> a -> Attribute action
- Miso.Html.Types: rawHtml :: MisoString -> View action
- Miso.Html.Types: runView :: View action -> Sink action -> JSM VTree
- Miso.Html.Types: style_ :: Map MisoString MisoString -> Attribute action
- Miso.Html.Types: text :: MisoString -> View action
- Miso.Html.Types: textRaw :: MisoString -> View action
- Miso.Html.Types: toKey :: ToKey key => key -> Key
- Miso.Html.Types: toView :: ToView v => v -> View action
- Miso.Router: Fail :: RoutingError
- Miso.Router: class HasRouter layout
- Miso.Router: instance (Miso.Router.HasRouter sublayout, GHC.TypeLits.KnownSymbol path) => Miso.Router.HasRouter (path Servant.API.Sub.:> sublayout)
- Miso.Router: instance (Miso.Router.HasRouter sublayout, GHC.TypeLits.KnownSymbol sym) => Miso.Router.HasRouter (Servant.API.QueryParam.QueryFlag sym Servant.API.Sub.:> sublayout)
- Miso.Router: instance (Miso.Router.HasRouter sublayout, Web.Internal.HttpApiData.FromHttpApiData x) => Miso.Router.HasRouter (Servant.API.Capture.Capture sym x Servant.API.Sub.:> sublayout)
- Miso.Router: instance (Miso.Router.HasRouter sublayout, Web.Internal.HttpApiData.FromHttpApiData x, GHC.TypeLits.KnownSymbol sym) => Miso.Router.HasRouter (Servant.API.QueryParam.QueryParam sym x Servant.API.Sub.:> sublayout)
- Miso.Router: instance (Miso.Router.HasRouter sublayout, Web.Internal.HttpApiData.FromHttpApiData x, GHC.TypeLits.KnownSymbol sym) => Miso.Router.HasRouter (Servant.API.QueryParam.QueryParams sym x Servant.API.Sub.:> sublayout)
- Miso.Router: instance (Miso.Router.HasRouter x, Miso.Router.HasRouter y) => Miso.Router.HasRouter (x Servant.API.Alternative.:<|> y)
- Miso.Router: instance GHC.Classes.Eq Miso.Router.Location
- Miso.Router: instance GHC.Classes.Ord Miso.Router.Location
- Miso.Router: instance GHC.Classes.Ord Miso.Router.RoutingError
- Miso.Router: instance GHC.Show.Show Miso.Router.Location
- Miso.Router: instance Miso.Router.HasRouter (Miso.Html.Types.View a)
- Miso.Router: instance Miso.Router.HasRouter Servant.API.Raw.Raw
- Miso.Router: instance Miso.Router.HasRouter sublayout => Miso.Router.HasRouter (Servant.API.Header.Header sym x Servant.API.Sub.:> sublayout)
- Miso.Router: instance forall k1 (m :: k1) (s :: GHC.TypeNats.Nat) (c :: [*]) a. Miso.Router.HasRouter (Servant.API.Verbs.Verb m s c a)
- Miso.Router: runRoute :: HasRouter layout => Proxy layout -> RouteT layout (m -> a) -> (m -> URI) -> m -> Either RoutingError a
- Miso.Router: type RouteT layout a :: *
- Miso.String: instance Miso.String.FromMisoString Data.JSString.Internal.Type.JSString
- Miso.String: instance Miso.String.FromMisoString Miso.String.MisoString
- Miso.String: instance Miso.String.ToMisoString Data.JSString.Internal.Type.JSString
- Miso.String: instance Miso.String.ToMisoString Miso.String.MisoString
- Miso.Subscription.History: [uriAuthority] :: URI -> Maybe URIAuth
- Miso.Subscription.History: [uriQuery] :: URI -> String
- Miso.Subscription.History: [uriScheme] :: URI -> String
- Miso.Subscription.History: getCurrentURI :: JSM URI
- Miso.Subscription.SSE: SSEClose :: SSE message
- Miso.Subscription.SSE: SSEError :: SSE message
- Miso.Subscription.SSE: SSEMessage :: message -> SSE message
- Miso.Subscription.SSE: data SSE message
- Miso.Subscription.SSE: instance GHC.Classes.Eq message => GHC.Classes.Eq (Miso.Subscription.SSE.SSE message)
- Miso.Subscription.SSE: instance GHC.Show.Show message => GHC.Show.Show (Miso.Subscription.SSE.SSE message)
- Miso.Subscription.SSE: sseSub :: FromJSON msg => MisoString -> (SSE msg -> action) -> Sub action
- Miso.Subscription.WebSocket: CLOSED :: SocketState
- Miso.Subscription.WebSocket: CLOSE_ABNORMAL :: CloseCode
- Miso.Subscription.WebSocket: CLOSE_GOING_AWAY :: CloseCode
- Miso.Subscription.WebSocket: CLOSE_NORMAL :: CloseCode
- Miso.Subscription.WebSocket: CLOSE_NO_STATUS :: CloseCode
- Miso.Subscription.WebSocket: CLOSE_PROTOCOL_ERROR :: CloseCode
- Miso.Subscription.WebSocket: CLOSE_TOO_LARGE :: CloseCode
- Miso.Subscription.WebSocket: CLOSE_UNSUPPORTED :: CloseCode
- Miso.Subscription.WebSocket: CLOSING :: SocketState
- Miso.Subscription.WebSocket: CONNECTING :: SocketState
- Miso.Subscription.WebSocket: Internal_Error :: CloseCode
- Miso.Subscription.WebSocket: Missing_Extension :: CloseCode
- Miso.Subscription.WebSocket: OPEN :: SocketState
- Miso.Subscription.WebSocket: OtherCode :: Int -> CloseCode
- Miso.Subscription.WebSocket: Policy_Violation :: CloseCode
- Miso.Subscription.WebSocket: Protocols :: [MisoString] -> Protocols
- Miso.Subscription.WebSocket: Reason :: MisoString -> Reason
- Miso.Subscription.WebSocket: Service_Restart :: CloseCode
- Miso.Subscription.WebSocket: TLS_Handshake :: CloseCode
- Miso.Subscription.WebSocket: Try_Again_Later :: CloseCode
- Miso.Subscription.WebSocket: URL :: MisoString -> URL
- Miso.Subscription.WebSocket: Unsupported_Data :: CloseCode
- Miso.Subscription.WebSocket: WasClean :: Bool -> WasClean
- Miso.Subscription.WebSocket: WebSocketClose :: CloseCode -> WasClean -> Reason -> WebSocket action
- Miso.Subscription.WebSocket: WebSocketError :: MisoString -> WebSocket action
- Miso.Subscription.WebSocket: WebSocketMessage :: action -> WebSocket action
- Miso.Subscription.WebSocket: WebSocketOpen :: WebSocket action
- Miso.Subscription.WebSocket: close :: JSM ()
- Miso.Subscription.WebSocket: connect :: URL -> Protocols -> JSM ()
- Miso.Subscription.WebSocket: data CloseCode
- Miso.Subscription.WebSocket: data SocketState
- Miso.Subscription.WebSocket: data WebSocket action
- Miso.Subscription.WebSocket: getSocketState :: JSM SocketState
- Miso.Subscription.WebSocket: newtype Protocols
- Miso.Subscription.WebSocket: newtype Reason
- Miso.Subscription.WebSocket: newtype URL
- Miso.Subscription.WebSocket: newtype WasClean
- Miso.Subscription.WebSocket: send :: ToJSON a => a -> JSM ()
- Miso.Subscription.WebSocket: websocketSub :: FromJSON m => URL -> Protocols -> (WebSocket m -> action) -> Sub action
- Miso.Svg: accelerate_ :: MisoString -> Attribute action
- Miso.Svg: accentHeight_ :: MisoString -> Attribute action
- Miso.Svg: accumulate_ :: MisoString -> Attribute action
- Miso.Svg: additive_ :: MisoString -> Attribute action
- Miso.Svg: alignmentBaseline_ :: MisoString -> Attribute action
- Miso.Svg: allowReorder_ :: MisoString -> Attribute action
- Miso.Svg: alphabetic_ :: MisoString -> Attribute action
- Miso.Svg: amplitude_ :: MisoString -> Attribute action
- Miso.Svg: arabicForm_ :: MisoString -> Attribute action
- Miso.Svg: ascent_ :: MisoString -> Attribute action
- Miso.Svg: attributeName_ :: MisoString -> Attribute action
- Miso.Svg: attributeType_ :: MisoString -> Attribute action
- Miso.Svg: autoReverse_ :: MisoString -> Attribute action
- Miso.Svg: azimuth_ :: MisoString -> Attribute action
- Miso.Svg: baseFrequency_ :: MisoString -> Attribute action
- Miso.Svg: baseProfile_ :: MisoString -> Attribute action
- Miso.Svg: baselineShift_ :: MisoString -> Attribute action
- Miso.Svg: bbox_ :: MisoString -> Attribute action
- Miso.Svg: begin_ :: MisoString -> Attribute action
- Miso.Svg: bias_ :: MisoString -> Attribute action
- Miso.Svg: by_ :: MisoString -> Attribute action
- Miso.Svg: calcMode_ :: MisoString -> Attribute action
- Miso.Svg: capHeight_ :: MisoString -> Attribute action
- Miso.Svg: class_' :: MisoString -> Attribute action
- Miso.Svg: clipPathUnits_ :: MisoString -> Attribute action
- Miso.Svg: clipRule_ :: MisoString -> Attribute action
- Miso.Svg: clip_ :: MisoString -> Attribute action
- Miso.Svg: colorInterpolationFilters_ :: MisoString -> Attribute action
- Miso.Svg: colorInterpolation_ :: MisoString -> Attribute action
- Miso.Svg: colorRendering_ :: MisoString -> Attribute action
- Miso.Svg: color_ :: MisoString -> Attribute action
- Miso.Svg: contentScriptType_ :: MisoString -> Attribute action
- Miso.Svg: contentStyleType_ :: MisoString -> Attribute action
- Miso.Svg: cx_ :: MisoString -> Attribute action
- Miso.Svg: cy_ :: MisoString -> Attribute action
- Miso.Svg: d_ :: MisoString -> Attribute action
- Miso.Svg: decelerate_ :: MisoString -> Attribute action
- Miso.Svg: descent_ :: MisoString -> Attribute action
- Miso.Svg: diffuseConstant_ :: MisoString -> Attribute action
- Miso.Svg: direction_ :: MisoString -> Attribute action
- Miso.Svg: display_ :: MisoString -> Attribute action
- Miso.Svg: divisor_ :: MisoString -> Attribute action
- Miso.Svg: dominantBaseline_ :: MisoString -> Attribute action
- Miso.Svg: dur_ :: MisoString -> Attribute action
- Miso.Svg: dx_ :: MisoString -> Attribute action
- Miso.Svg: dy_ :: MisoString -> Attribute action
- Miso.Svg: edgeMode_ :: MisoString -> Attribute action
- Miso.Svg: elevation_ :: MisoString -> Attribute action
- Miso.Svg: enableBackground_ :: MisoString -> Attribute action
- Miso.Svg: end_ :: MisoString -> Attribute action
- Miso.Svg: exponent_ :: MisoString -> Attribute action
- Miso.Svg: externalResourcesRequired_ :: MisoString -> Attribute action
- Miso.Svg: fillOpacity_ :: MisoString -> Attribute action
- Miso.Svg: fillRule_ :: MisoString -> Attribute action
- Miso.Svg: fill_ :: MisoString -> Attribute action
- Miso.Svg: filterRes_ :: MisoString -> Attribute action
- Miso.Svg: filterUnits_ :: MisoString -> Attribute action
- Miso.Svg: floodColor_ :: MisoString -> Attribute action
- Miso.Svg: floodOpacity_ :: MisoString -> Attribute action
- Miso.Svg: fontFamily_ :: MisoString -> Attribute action
- Miso.Svg: fontSizeAdjust_ :: MisoString -> Attribute action
- Miso.Svg: fontSize_ :: MisoString -> Attribute action
- Miso.Svg: fontStretch_ :: MisoString -> Attribute action
- Miso.Svg: fontStyle_ :: MisoString -> Attribute action
- Miso.Svg: fontVariant_ :: MisoString -> Attribute action
- Miso.Svg: fontWeight_ :: MisoString -> Attribute action
- Miso.Svg: format_ :: MisoString -> Attribute action
- Miso.Svg: from_ :: MisoString -> Attribute action
- Miso.Svg: fx_ :: MisoString -> Attribute action
- Miso.Svg: fy_ :: MisoString -> Attribute action
- Miso.Svg: g1_ :: MisoString -> Attribute action
- Miso.Svg: g2_ :: MisoString -> Attribute action
- Miso.Svg: glyphName_ :: MisoString -> Attribute action
- Miso.Svg: glyphOrientationHorizontal_ :: MisoString -> Attribute action
- Miso.Svg: glyphOrientationVertical_ :: MisoString -> Attribute action
- Miso.Svg: gradientTransform_ :: MisoString -> Attribute action
- Miso.Svg: gradientUnits_ :: MisoString -> Attribute action
- Miso.Svg: hanging_ :: MisoString -> Attribute action
- Miso.Svg: height_ :: MisoString -> Attribute action
- Miso.Svg: horizAdvX_ :: MisoString -> Attribute action
- Miso.Svg: horizOriginX_ :: MisoString -> Attribute action
- Miso.Svg: horizOriginY_ :: MisoString -> Attribute action
- Miso.Svg: id_ :: MisoString -> Attribute action
- Miso.Svg: ideographic_ :: MisoString -> Attribute action
- Miso.Svg: imageRendering_ :: MisoString -> Attribute action
- Miso.Svg: in2_ :: MisoString -> Attribute action
- Miso.Svg: in_' :: MisoString -> Attribute action
- Miso.Svg: intercept_ :: MisoString -> Attribute action
- Miso.Svg: k1_ :: MisoString -> Attribute action
- Miso.Svg: k2_ :: MisoString -> Attribute action
- Miso.Svg: k3_ :: MisoString -> Attribute action
- Miso.Svg: k4_ :: MisoString -> Attribute action
- Miso.Svg: k_ :: MisoString -> Attribute action
- Miso.Svg: kernelMatrix_ :: MisoString -> Attribute action
- Miso.Svg: kernelUnitLength_ :: MisoString -> Attribute action
- Miso.Svg: kerning_ :: MisoString -> Attribute action
- Miso.Svg: keyPoints_ :: MisoString -> Attribute action
- Miso.Svg: keySplines_ :: MisoString -> Attribute action
- Miso.Svg: keyTimes_ :: MisoString -> Attribute action
- Miso.Svg: lang_ :: MisoString -> Attribute action
- Miso.Svg: lengthAdjust_ :: MisoString -> Attribute action
- Miso.Svg: letterSpacing_ :: MisoString -> Attribute action
- Miso.Svg: lightingColor_ :: MisoString -> Attribute action
- Miso.Svg: limitingConeAngle_ :: MisoString -> Attribute action
- Miso.Svg: local_ :: MisoString -> Attribute action
- Miso.Svg: markerEnd_ :: MisoString -> Attribute action
- Miso.Svg: markerHeight_ :: MisoString -> Attribute action
- Miso.Svg: markerMid_ :: MisoString -> Attribute action
- Miso.Svg: markerStart_ :: MisoString -> Attribute action
- Miso.Svg: markerUnits_ :: MisoString -> Attribute action
- Miso.Svg: markerWidth_ :: MisoString -> Attribute action
- Miso.Svg: maskContentUnits_ :: MisoString -> Attribute action
- Miso.Svg: maskUnits_ :: MisoString -> Attribute action
- Miso.Svg: mathematical_ :: MisoString -> Attribute action
- Miso.Svg: max_ :: MisoString -> Attribute action
- Miso.Svg: media_ :: MisoString -> Attribute action
- Miso.Svg: method_ :: MisoString -> Attribute action
- Miso.Svg: min_ :: MisoString -> Attribute action
- Miso.Svg: mode_ :: MisoString -> Attribute action
- Miso.Svg: name_ :: MisoString -> Attribute action
- Miso.Svg: numOctaves_ :: MisoString -> Attribute action
- Miso.Svg: offset_ :: MisoString -> Attribute action
- Miso.Svg: opacity_ :: MisoString -> Attribute action
- Miso.Svg: operator_ :: MisoString -> Attribute action
- Miso.Svg: order_ :: MisoString -> Attribute action
- Miso.Svg: orient_ :: MisoString -> Attribute action
- Miso.Svg: orientation_ :: MisoString -> Attribute action
- Miso.Svg: origin_ :: MisoString -> Attribute action
- Miso.Svg: overflow_ :: MisoString -> Attribute action
- Miso.Svg: overlinePosition_ :: MisoString -> Attribute action
- Miso.Svg: overlineThickness_ :: MisoString -> Attribute action
- Miso.Svg: panose1_ :: MisoString -> Attribute action
- Miso.Svg: pathLength_ :: MisoString -> Attribute action
- Miso.Svg: patternContentUnits_ :: MisoString -> Attribute action
- Miso.Svg: patternTransform_ :: MisoString -> Attribute action
- Miso.Svg: patternUnits_ :: MisoString -> Attribute action
- Miso.Svg: pointOrder_ :: MisoString -> Attribute action
- Miso.Svg: pointerEvents_ :: MisoString -> Attribute action
- Miso.Svg: pointsAtX_ :: MisoString -> Attribute action
- Miso.Svg: pointsAtY_ :: MisoString -> Attribute action
- Miso.Svg: pointsAtZ_ :: MisoString -> Attribute action
- Miso.Svg: points_ :: MisoString -> Attribute action
- Miso.Svg: preserveAlpha_ :: MisoString -> Attribute action
- Miso.Svg: preserveAspectRatio_ :: MisoString -> Attribute action
- Miso.Svg: primitiveUnits_ :: MisoString -> Attribute action
- Miso.Svg: r_ :: MisoString -> Attribute action
- Miso.Svg: radius_ :: MisoString -> Attribute action
- Miso.Svg: refX_ :: MisoString -> Attribute action
- Miso.Svg: refY_ :: MisoString -> Attribute action
- Miso.Svg: renderingIntent_ :: MisoString -> Attribute action
- Miso.Svg: repeatCount_ :: MisoString -> Attribute action
- Miso.Svg: repeatDur_ :: MisoString -> Attribute action
- Miso.Svg: requiredExtensions_ :: MisoString -> Attribute action
- Miso.Svg: requiredFeatures_ :: MisoString -> Attribute action
- Miso.Svg: restart_ :: MisoString -> Attribute action
- Miso.Svg: result_ :: MisoString -> Attribute action
- Miso.Svg: rotate_ :: MisoString -> Attribute action
- Miso.Svg: rx_ :: MisoString -> Attribute action
- Miso.Svg: ry_ :: MisoString -> Attribute action
- Miso.Svg: scale_ :: MisoString -> Attribute action
- Miso.Svg: seed_ :: MisoString -> Attribute action
- Miso.Svg: shapeRendering_ :: MisoString -> Attribute action
- Miso.Svg: slope_ :: MisoString -> Attribute action
- Miso.Svg: spacing_ :: MisoString -> Attribute action
- Miso.Svg: specularConstant_ :: MisoString -> Attribute action
- Miso.Svg: specularExponent_ :: MisoString -> Attribute action
- Miso.Svg: speed_ :: MisoString -> Attribute action
- Miso.Svg: spreadMethod_ :: MisoString -> Attribute action
- Miso.Svg: startOffset_ :: MisoString -> Attribute action
- Miso.Svg: stdDeviation_ :: MisoString -> Attribute action
- Miso.Svg: stemh_ :: MisoString -> Attribute action
- Miso.Svg: stemv_ :: MisoString -> Attribute action
- Miso.Svg: stitchTiles_ :: MisoString -> Attribute action
- Miso.Svg: stopColor_ :: MisoString -> Attribute action
- Miso.Svg: stopOpacity_ :: MisoString -> Attribute action
- Miso.Svg: strikethroughPosition_ :: MisoString -> Attribute action
- Miso.Svg: strikethroughThickness_ :: MisoString -> Attribute action
- Miso.Svg: string_ :: MisoString -> Attribute action
- Miso.Svg: strokeDasharray_ :: MisoString -> Attribute action
- Miso.Svg: strokeDashoffset_ :: MisoString -> Attribute action
- Miso.Svg: strokeLinecap_ :: MisoString -> Attribute action
- Miso.Svg: strokeLinejoin_ :: MisoString -> Attribute action
- Miso.Svg: strokeMiterlimit_ :: MisoString -> Attribute action
- Miso.Svg: strokeOpacity_ :: MisoString -> Attribute action
- Miso.Svg: strokeWidth_ :: MisoString -> Attribute action
- Miso.Svg: stroke_ :: MisoString -> Attribute action
- Miso.Svg: surfaceScale_ :: MisoString -> Attribute action
- Miso.Svg: systemLanguage_ :: MisoString -> Attribute action
- Miso.Svg: tableValues_ :: MisoString -> Attribute action
- Miso.Svg: targetX_ :: MisoString -> Attribute action
- Miso.Svg: targetY_ :: MisoString -> Attribute action
- Miso.Svg: target_ :: MisoString -> Attribute action
- Miso.Svg: textAnchor_ :: MisoString -> Attribute action
- Miso.Svg: textDecoration_ :: MisoString -> Attribute action
- Miso.Svg: textLength_ :: MisoString -> Attribute action
- Miso.Svg: textRendering_ :: MisoString -> Attribute action
- Miso.Svg: to_ :: MisoString -> Attribute action
- Miso.Svg: transform_ :: MisoString -> Attribute action
- Miso.Svg: type_' :: MisoString -> Attribute action
- Miso.Svg: u1_ :: MisoString -> Attribute action
- Miso.Svg: u2_ :: MisoString -> Attribute action
- Miso.Svg: underlinePosition_ :: MisoString -> Attribute action
- Miso.Svg: underlineThickness_ :: MisoString -> Attribute action
- Miso.Svg: unicodeBidi_ :: MisoString -> Attribute action
- Miso.Svg: unicodeRange_ :: MisoString -> Attribute action
- Miso.Svg: unicode_ :: MisoString -> Attribute action
- Miso.Svg: unitsPerEm_ :: MisoString -> Attribute action
- Miso.Svg: vAlphabetic_ :: MisoString -> Attribute action
- Miso.Svg: vHanging_ :: MisoString -> Attribute action
- Miso.Svg: vIdeographic_ :: MisoString -> Attribute action
- Miso.Svg: vMathematical_ :: MisoString -> Attribute action
- Miso.Svg: values_ :: MisoString -> Attribute action
- Miso.Svg: version_ :: MisoString -> Attribute action
- Miso.Svg: vertAdvY_ :: MisoString -> Attribute action
- Miso.Svg: vertOriginX_ :: MisoString -> Attribute action
- Miso.Svg: vertOriginY_ :: MisoString -> Attribute action
- Miso.Svg: viewBox_ :: MisoString -> Attribute action
- Miso.Svg: viewTarget_ :: MisoString -> Attribute action
- Miso.Svg: visibility_ :: MisoString -> Attribute action
- Miso.Svg: width_ :: MisoString -> Attribute action
- Miso.Svg: widths_ :: MisoString -> Attribute action
- Miso.Svg: wordSpacing_ :: MisoString -> Attribute action
- Miso.Svg: writingMode_ :: MisoString -> Attribute action
- Miso.Svg: x1_ :: MisoString -> Attribute action
- Miso.Svg: x2_ :: MisoString -> Attribute action
- Miso.Svg: xChannelSelector_ :: MisoString -> Attribute action
- Miso.Svg: xHeight_ :: MisoString -> Attribute action
- Miso.Svg: x_ :: MisoString -> Attribute action
- Miso.Svg: xlinkActuate_ :: MisoString -> Attribute action
- Miso.Svg: xlinkArcrole_ :: MisoString -> Attribute action
- Miso.Svg: xlinkHref_ :: MisoString -> Attribute action
- Miso.Svg: xlinkRole_ :: MisoString -> Attribute action
- Miso.Svg: xlinkShow_ :: MisoString -> Attribute action
- Miso.Svg: xlinkTitle_ :: MisoString -> Attribute action
- Miso.Svg: xlinkType_ :: MisoString -> Attribute action
- Miso.Svg: xmlBase_ :: MisoString -> Attribute action
- Miso.Svg: xmlLang_ :: MisoString -> Attribute action
- Miso.Svg: xmlSpace_ :: MisoString -> Attribute action
- Miso.Svg: y1_ :: MisoString -> Attribute action
- Miso.Svg: y2_ :: MisoString -> Attribute action
- Miso.Svg: yChannelSelector_ :: MisoString -> Attribute action
- Miso.Svg: y_ :: MisoString -> Attribute action
- Miso.Svg: z_ :: MisoString -> Attribute action
- Miso.Svg: zoomAndPan_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: accelerate_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: accentHeight_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: accumulate_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: additive_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: alignmentBaseline_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: allowReorder_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: alphabetic_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: amplitude_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: arabicForm_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: ascent_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: attributeName_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: attributeType_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: autoReverse_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: azimuth_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: baseFrequency_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: baseProfile_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: baselineShift_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: bbox_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: begin_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: bias_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: by_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: calcMode_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: capHeight_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: class_' :: MisoString -> Attribute action
- Miso.Svg.Attribute: clipPathUnits_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: clipPath_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: clipRule_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: clip_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: colorInterpolationFilters_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: colorInterpolation_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: colorProfile_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: colorRendering_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: color_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: contentScriptType_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: contentStyleType_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: cursor_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: cx_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: cy_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: d_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: decelerate_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: descent_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: diffuseConstant_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: direction_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: display_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: divisor_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: dominantBaseline_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: dur_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: dx_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: dy_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: edgeMode_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: elevation_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: enableBackground_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: end_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: exponent_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: externalResourcesRequired_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: fillOpacity_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: fillRule_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: fill_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: filterRes_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: filterUnits_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: filter_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: floodColor_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: floodOpacity_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: fontFamily_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: fontSizeAdjust_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: fontSize_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: fontStretch_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: fontStyle_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: fontVariant_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: fontWeight_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: format_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: from_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: fx_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: fy_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: g1_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: g2_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: glyphName_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: glyphOrientationHorizontal_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: glyphOrientationVertical_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: glyphRef_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: gradientTransform_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: gradientUnits_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: hanging_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: height_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: horizAdvX_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: horizOriginX_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: horizOriginY_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: id_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: ideographic_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: imageRendering_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: in2_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: in_' :: MisoString -> Attribute action
- Miso.Svg.Attribute: intercept_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: k1_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: k2_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: k3_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: k4_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: k_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: kernelMatrix_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: kernelUnitLength_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: kerning_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: keyPoints_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: keySplines_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: keyTimes_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: lang_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: lengthAdjust_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: letterSpacing_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: lightingColor_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: limitingConeAngle_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: local_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: markerEnd_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: markerHeight_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: markerMid_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: markerStart_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: markerUnits_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: markerWidth_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: maskContentUnits_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: maskUnits_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: mask_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: mathematical_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: max_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: media_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: method_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: min_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: mode_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: name_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: numOctaves_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: offset_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: opacity_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: operator_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: order_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: orient_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: orientation_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: origin_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: overflow_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: overlinePosition_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: overlineThickness_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: panose1_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: pathLength_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: path_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: patternContentUnits_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: patternTransform_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: patternUnits_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: pointOrder_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: pointerEvents_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: pointsAtX_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: pointsAtY_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: pointsAtZ_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: points_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: preserveAlpha_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: preserveAspectRatio_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: primitiveUnits_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: r_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: radius_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: refX_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: refY_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: renderingIntent_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: repeatCount_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: repeatDur_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: requiredExtensions_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: requiredFeatures_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: restart_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: result_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: rotate_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: rx_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: ry_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: scale_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: seed_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: shapeRendering_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: slope_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: spacing_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: specularConstant_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: specularExponent_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: speed_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: spreadMethod_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: startOffset_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: stdDeviation_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: stemh_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: stemv_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: stitchTiles_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: stopColor_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: stopOpacity_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: strikethroughPosition_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: strikethroughThickness_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: string_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: strokeDasharray_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: strokeDashoffset_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: strokeLinecap_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: strokeLinejoin_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: strokeMiterlimit_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: strokeOpacity_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: strokeWidth_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: stroke_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: style_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: surfaceScale_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: systemLanguage_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: tableValues_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: targetX_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: targetY_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: target_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: textAnchor_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: textDecoration_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: textLength_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: textRendering_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: title_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: to_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: transform_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: type_' :: MisoString -> Attribute action
- Miso.Svg.Attribute: u1_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: u2_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: underlinePosition_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: underlineThickness_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: unicodeBidi_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: unicodeRange_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: unicode_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: unitsPerEm_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: vAlphabetic_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: vHanging_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: vIdeographic_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: vMathematical_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: values_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: version_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: vertAdvY_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: vertOriginX_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: vertOriginY_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: viewBox_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: viewTarget_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: visibility_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: width_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: widths_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: wordSpacing_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: writingMode_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: x1_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: x2_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: xChannelSelector_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: xHeight_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: x_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: xlinkActuate_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: xlinkArcrole_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: xlinkHref_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: xlinkRole_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: xlinkShow_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: xlinkTitle_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: xlinkType_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: xmlBase_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: xmlLang_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: xmlSpace_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: y1_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: y2_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: yChannelSelector_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: y_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: z_ :: MisoString -> Attribute action
- Miso.Svg.Attribute: zoomAndPan_ :: MisoString -> Attribute action
- Miso.Svg.Element: a_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: altGlyphDef_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: altGlyphItem_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: altGlyph_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: animateColor_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: colorProfile_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: cursor_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: feMorhpology_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: fontFaceFormat_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: fontFaceName_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: fontFaceSrc_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: fontFaceUri_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: fontFace_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: font_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: glyphRef_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: glyph_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: hkern_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: missingGlyph_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: tref_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Element: vkern_ :: [Attribute action] -> [View action] -> View action
- Miso.Svg.Event: onLoad :: action -> Attribute action
- Miso.Svg.Event: onUnload :: action -> Attribute action
- Miso.TypeLevel: type family ToServerRoutes (layout :: k) (wrapper :: * -> *) (action :: *) :: k
- Miso.Types: App :: model -> (action -> model -> Effect action model) -> (model -> View action) -> [Sub action] -> Map MisoString Bool -> action -> Maybe MisoString -> LogLevel -> App model action
- Miso.Types: DebugPrerender :: LogLevel
- Miso.Types: [events] :: App model action -> Map MisoString Bool
- Miso.Types: [initialAction] :: App model action -> action
- Miso.Types: data App model action
- Miso.Types: data Effect action model
- Miso.Types: fromTransition :: Transition action model () -> model -> Effect action model
- Miso.Types: mapAction :: (actionA -> actionB) -> Transition actionA model r -> Transition actionB model r
- Miso.Types: scheduleIO :: JSM action -> Transition action model ()
- Miso.Types: scheduleIOFor_ :: Foldable f => JSM (f action) -> Transition action model ()
- Miso.Types: scheduleIO_ :: JSM () -> Transition action model ()
- Miso.Types: scheduleSub :: Sub action -> Transition action model ()
- Miso.Types: toTransition :: (model -> Effect action model) -> Transition action model ()
- Miso.Types: type Sub action = Sink action -> JSM ()
- Miso.Types: type Transition action model = StateT model (Writer [Sub action])
- Miso.WebSocket: Protocols :: [MisoString] -> Protocols
- Miso.WebSocket: Reason :: MisoString -> Reason
- Miso.WebSocket: URL :: MisoString -> URL
- Miso.WebSocket: WasClean :: Bool -> WasClean
- Miso.WebSocket: WebSocketClose :: CloseCode -> WasClean -> Reason -> WebSocket action
- Miso.WebSocket: WebSocketError :: MisoString -> WebSocket action
- Miso.WebSocket: WebSocketMessage :: action -> WebSocket action
- Miso.WebSocket: WebSocketOpen :: WebSocket action
- Miso.WebSocket: data WebSocket action
- Miso.WebSocket: instance GHC.Classes.Eq Miso.WebSocket.CloseCode
- Miso.WebSocket: instance GHC.Classes.Eq Miso.WebSocket.Protocols
- Miso.WebSocket: instance GHC.Classes.Eq Miso.WebSocket.Reason
- Miso.WebSocket: instance GHC.Classes.Eq Miso.WebSocket.SocketState
- Miso.WebSocket: instance GHC.Classes.Eq Miso.WebSocket.URL
- Miso.WebSocket: instance GHC.Classes.Eq Miso.WebSocket.WasClean
- Miso.WebSocket: instance GHC.Classes.Eq action => GHC.Classes.Eq (Miso.WebSocket.WebSocket action)
- Miso.WebSocket: instance GHC.Classes.Ord Miso.WebSocket.SocketState
- Miso.WebSocket: instance GHC.Enum.Enum Miso.WebSocket.SocketState
- Miso.WebSocket: instance GHC.Generics.Generic Miso.WebSocket.CloseCode
- Miso.WebSocket: instance GHC.Show.Show Miso.WebSocket.CloseCode
- Miso.WebSocket: instance GHC.Show.Show Miso.WebSocket.Protocols
- Miso.WebSocket: instance GHC.Show.Show Miso.WebSocket.Reason
- Miso.WebSocket: instance GHC.Show.Show Miso.WebSocket.SocketState
- Miso.WebSocket: instance GHC.Show.Show Miso.WebSocket.URL
- Miso.WebSocket: instance GHC.Show.Show Miso.WebSocket.WasClean
- Miso.WebSocket: instance GHC.Show.Show action => GHC.Show.Show (Miso.WebSocket.WebSocket action)
- Miso.WebSocket: newtype Protocols
- Miso.WebSocket: newtype Reason
- Miso.WebSocket: newtype URL
- Miso.WebSocket: newtype WasClean
+ Miso: (+>) :: Eq child => MisoString -> Component model child action -> View model a
+ Miso: (🍜) :: Eq model => Events -> (URI -> App model action) -> IO ()
+ Miso: Component :: model -> Maybe (IO model) -> (action -> Effect parent model action) -> (model -> View model action) -> [Sub action] -> [CSS] -> [JS] -> Maybe MountPoint -> LogLevel -> (Value -> Maybe action) -> [Binding parent model] -> Bool -> Maybe action -> Maybe action -> Component parent model action
+ Miso: [bindings] :: Component parent model action -> [Binding parent model]
+ Miso: [eventPropagation] :: Component parent model action -> Bool
+ Miso: [hydrateModel] :: Component parent model action -> Maybe (IO model)
+ Miso: [logLevel] :: Component parent model action -> LogLevel
+ Miso: [mailbox] :: Component parent model action -> Value -> Maybe action
+ Miso: [model] :: Component parent model action -> model
+ Miso: [mountPoint] :: Component parent model action -> Maybe MountPoint
+ Miso: [mount] :: Component parent model action -> Maybe action
+ Miso: [scripts] :: Component parent model action -> [JS]
+ Miso: [styles] :: Component parent model action -> [CSS]
+ Miso: [subs] :: Component parent model action -> [Sub action]
+ Miso: [unmount] :: Component parent model action -> Maybe action
+ Miso: [update] :: Component parent model action -> action -> Effect parent model action
+ Miso: [view] :: Component parent model action -> model -> View model action
+ Miso: batch :: [IO action] -> Effect parent model action
+ Miso: broadcast :: (Eq model, ToJSON message) => message -> Effect parent model action
+ Miso: checkMail :: FromJSON value => (value -> action) -> (MisoString -> action) -> Value -> Maybe action
+ Miso: component :: model -> (action -> Effect parent model action) -> (model -> View model action) -> Component parent model action
+ Miso: data Component parent model action
+ Miso: for :: Foldable f => IO (f action) -> Effect parent model action
+ Miso: infixr 0 +>
+ Miso: io :: IO action -> Effect parent model action
+ Miso: io_ :: IO () -> Effect parent model action
+ Miso: issue :: action -> Effect parent model action
+ Miso: mail :: ToJSON message => ComponentId -> message -> IO ()
+ Miso: mailParent :: ToJSON message => message -> Effect parent model action
+ Miso: mount_ :: Eq child => Component model child a -> View model action
+ Miso: parent :: (parent -> action) -> action -> Effect parent model action
+ Miso: prerender :: Eq model => Events -> App model action -> IO ()
+ Miso: renderApp :: Eq model => Events -> MisoString -> App model action -> IO ()
+ Miso: startSub :: ToMisoString subKey => subKey -> Sub action -> Effect parent model action
+ Miso: stopSub :: ToMisoString subKey => subKey -> Effect parent model action
+ Miso: sync :: IO action -> Effect parent model action
+ Miso: sync_ :: IO () -> Effect parent model action
+ Miso: type App model action = Component ROOT model action
+ Miso: type Sink action = action -> IO ()
+ Miso: type Sub action = Sink action -> IO ()
+ Miso: vcomp :: model -> (action -> Effect parent model action) -> (model -> View model action) -> Component parent model action
+ Miso: vnode :: Namespace -> MisoString -> [Attribute action] -> [View model action] -> View model action
+ Miso: vtext :: MisoString -> View model action
+ Miso: withJS :: IO a -> IO a
+ Miso: withSink :: (Sink action -> IO ()) -> Effect parent model action
+ Miso.Binding: (--->) :: Lens' parent field -> Lens' child field -> Binding parent child
+ Miso.Binding: (-->) :: Lens parent a -> Lens model a -> Binding parent model
+ Miso.Binding: (<--) :: Lens parent a -> Lens model a -> Binding parent model
+ Miso.Binding: (<---) :: Lens' parent field -> Lens' child field -> Binding parent child
+ Miso.Binding: (<--->) :: Lens' parent field -> Lens' child field -> Binding parent child
+ Miso.Binding: (<-->) :: Lens parent field -> Lens child field -> Binding parent child
+ Miso.Binding: Bidirectional :: (parent -> field) -> (field -> parent -> parent) -> (child -> field) -> (field -> child -> child) -> Binding parent child
+ Miso.Binding: ChildToParent :: (field -> parent -> parent) -> (child -> field) -> Binding parent child
+ Miso.Binding: ParentToChild :: (parent -> field) -> (field -> child -> child) -> Binding parent child
+ Miso.Binding: data Binding parent child
+ Miso.Binding: infix 0 <--->
+ Miso.Binding: infixl 0 <---
+ Miso.Binding: infixr 0 --->
+ Miso.CSS: alignContent :: MisoString -> Style
+ Miso.CSS: alignItems :: MisoString -> Style
+ Miso.CSS: alignSelf :: MisoString -> Style
+ Miso.CSS: animation :: MisoString -> Style
+ Miso.CSS: animationDelay :: MisoString -> Style
+ Miso.CSS: animationDirection :: MisoString -> Style
+ Miso.CSS: animationDuration :: MisoString -> Style
+ Miso.CSS: animationFillMode :: MisoString -> Style
+ Miso.CSS: animationIterationCount :: MisoString -> Style
+ Miso.CSS: animationName :: MisoString -> Style
+ Miso.CSS: animationPlayState :: MisoString -> Style
+ Miso.CSS: animationTimingFunction :: MisoString -> Style
+ Miso.CSS: aspectRatio :: MisoString -> Style
+ Miso.CSS: background :: MisoString -> Style
+ Miso.CSS: backgroundClip :: MisoString -> Style
+ Miso.CSS: backgroundColor :: Color -> Style
+ Miso.CSS: backgroundImage :: MisoString -> Style
+ Miso.CSS: backgroundOrigin :: MisoString -> Style
+ Miso.CSS: backgroundPosition :: MisoString -> Style
+ Miso.CSS: backgroundRepeat :: MisoString -> Style
+ Miso.CSS: backgroundSize :: MisoString -> Style
+ Miso.CSS: border :: MisoString -> Style
+ Miso.CSS: borderBottom :: MisoString -> Style
+ Miso.CSS: borderBottomColor :: Color -> Style
+ Miso.CSS: borderBottomLeftRadius :: MisoString -> Style
+ Miso.CSS: borderBottomRightRadius :: MisoString -> Style
+ Miso.CSS: borderBottomStyle :: MisoString -> Style
+ Miso.CSS: borderBottomWidth :: MisoString -> Style
+ Miso.CSS: borderCollapse :: MisoString -> Style
+ Miso.CSS: borderColor :: Color -> Style
+ Miso.CSS: borderEndEndRadius :: MisoString -> Style
+ Miso.CSS: borderEndStartRadius :: MisoString -> Style
+ Miso.CSS: borderInlineEndColor :: Color -> Style
+ Miso.CSS: borderInlineEndStyle :: MisoString -> Style
+ Miso.CSS: borderInlineEndWidth :: MisoString -> Style
+ Miso.CSS: borderInlineStartColor :: Color -> Style
+ Miso.CSS: borderInlineStartStyle :: MisoString -> Style
+ Miso.CSS: borderInlineStartWidth :: MisoString -> Style
+ Miso.CSS: borderLeft :: MisoString -> Style
+ Miso.CSS: borderLeftColor :: Color -> Style
+ Miso.CSS: borderLeftStyle :: MisoString -> Style
+ Miso.CSS: borderLeftWidth :: MisoString -> Style
+ Miso.CSS: borderRadius :: MisoString -> Style
+ Miso.CSS: borderRight :: MisoString -> Style
+ Miso.CSS: borderRightColor :: Color -> Style
+ Miso.CSS: borderRightStyle :: MisoString -> Style
+ Miso.CSS: borderRightWidth :: MisoString -> Style
+ Miso.CSS: borderStartEndRadius :: MisoString -> Style
+ Miso.CSS: borderStartStartRadius :: MisoString -> Style
+ Miso.CSS: borderStyle :: MisoString -> Style
+ Miso.CSS: borderTop :: MisoString -> Style
+ Miso.CSS: borderTopColor :: Color -> Style
+ Miso.CSS: borderTopLeftRadius :: MisoString -> Style
+ Miso.CSS: borderTopRightRadius :: MisoString -> Style
+ Miso.CSS: borderTopStyle :: MisoString -> Style
+ Miso.CSS: borderTopWidth :: MisoString -> Style
+ Miso.CSS: borderWidth :: MisoString -> Style
+ Miso.CSS: bottom :: MisoString -> Style
+ Miso.CSS: boxShadow :: MisoString -> Style
+ Miso.CSS: boxSizing :: MisoString -> Style
+ Miso.CSS: clipPath :: MisoString -> Style
+ Miso.CSS: color :: Color -> Style
+ Miso.CSS: columnGap :: MisoString -> Style
+ Miso.CSS: cssVariable :: MisoString -> Style
+ Miso.CSS: cursor :: MisoString -> Style
+ Miso.CSS: deg :: Double -> MisoString
+ Miso.CSS: direction :: MisoString -> Style
+ Miso.CSS: display :: MisoString -> Style
+ Miso.CSS: em :: Double -> MisoString
+ Miso.CSS: fill :: MisoString -> Style
+ Miso.CSS: filter :: MisoString -> Style
+ Miso.CSS: flex :: MisoString -> Style
+ Miso.CSS: flexBasis :: MisoString -> Style
+ Miso.CSS: flexDirection :: MisoString -> Style
+ Miso.CSS: flexFlow :: MisoString -> Style
+ Miso.CSS: flexGrow :: MisoString -> Style
+ Miso.CSS: flexShrink :: MisoString -> Style
+ Miso.CSS: flexWrap :: MisoString -> Style
+ Miso.CSS: fontFamily :: MisoString -> Style
+ Miso.CSS: fontSize :: MisoString -> Style
+ Miso.CSS: fontStyle :: MisoString -> Style
+ Miso.CSS: fontWeight :: MisoString -> Style
+ Miso.CSS: gap :: MisoString -> Style
+ Miso.CSS: gridAutoColumns :: MisoString -> Style
+ Miso.CSS: gridAutoFlow :: MisoString -> Style
+ Miso.CSS: gridAutoRows :: MisoString -> Style
+ Miso.CSS: gridColumnEnd :: MisoString -> Style
+ Miso.CSS: gridColumnSpan :: MisoString -> Style
+ Miso.CSS: gridColumnStart :: MisoString -> Style
+ Miso.CSS: gridRowEnd :: MisoString -> Style
+ Miso.CSS: gridRowSpan :: MisoString -> Style
+ Miso.CSS: gridRowStart :: MisoString -> Style
+ Miso.CSS: gridTemplateColumns :: MisoString -> Style
+ Miso.CSS: gridTemplateRows :: MisoString -> Style
+ Miso.CSS: height :: MisoString -> Style
+ Miso.CSS: imageRendering :: MisoString -> Style
+ Miso.CSS: insetInlineEnd :: MisoString -> Style
+ Miso.CSS: insetInlineStart :: MisoString -> Style
+ Miso.CSS: justifyContent :: MisoString -> Style
+ Miso.CSS: justifyItems :: MisoString -> Style
+ Miso.CSS: justifySelf :: MisoString -> Style
+ Miso.CSS: keyframes_ :: MisoString -> [(MisoString, [Style])] -> Styles
+ Miso.CSS: left :: MisoString -> Style
+ Miso.CSS: letterSpacing :: MisoString -> Style
+ Miso.CSS: lineHeight :: MisoString -> Style
+ Miso.CSS: linearCrossGravity :: MisoString -> Style
+ Miso.CSS: linearDirection :: MisoString -> Style
+ Miso.CSS: linearGravity :: MisoString -> Style
+ Miso.CSS: linearLayoutGravity :: MisoString -> Style
+ Miso.CSS: linearWeight :: MisoString -> Style
+ Miso.CSS: linearWeightSum :: MisoString -> Style
+ Miso.CSS: margin :: MisoString -> Style
+ Miso.CSS: marginBottom :: MisoString -> Style
+ Miso.CSS: marginInlineEnd :: MisoString -> Style
+ Miso.CSS: marginInlineStart :: MisoString -> Style
+ Miso.CSS: marginLeft :: MisoString -> Style
+ Miso.CSS: marginRight :: MisoString -> Style
+ Miso.CSS: marginTop :: MisoString -> Style
+ Miso.CSS: mask :: MisoString -> Style
+ Miso.CSS: maskImage :: MisoString -> Style
+ Miso.CSS: matrix :: Double -> Double -> Double -> Double -> Double -> Double -> MisoString
+ Miso.CSS: maxHeight :: MisoString -> Style
+ Miso.CSS: maxWidth :: MisoString -> Style
+ Miso.CSS: media_ :: MisoString -> [(MisoString, [Style])] -> Styles
+ Miso.CSS: minHeight :: MisoString -> Style
+ Miso.CSS: minWidth :: MisoString -> Style
+ Miso.CSS: ms :: Double -> MisoString
+ Miso.CSS: opacity :: MisoString -> Style
+ Miso.CSS: order :: MisoString -> Style
+ Miso.CSS: overflow :: MisoString -> Style
+ Miso.CSS: overflowX :: MisoString -> Style
+ Miso.CSS: overflowY :: MisoString -> Style
+ Miso.CSS: padding :: MisoString -> Style
+ Miso.CSS: paddingBottom :: MisoString -> Style
+ Miso.CSS: paddingInlineEnd :: MisoString -> Style
+ Miso.CSS: paddingInlineStart :: MisoString -> Style
+ Miso.CSS: paddingLeft :: MisoString -> Style
+ Miso.CSS: paddingRight :: MisoString -> Style
+ Miso.CSS: paddingTop :: MisoString -> Style
+ Miso.CSS: pct :: Double -> MisoString
+ Miso.CSS: perspective :: MisoString -> Style
+ Miso.CSS: position :: MisoString -> Style
+ Miso.CSS: ppx :: Double -> MisoString
+ Miso.CSS: pt :: Int -> MisoString
+ Miso.CSS: px :: Int -> MisoString
+ Miso.CSS: rad :: Double -> MisoString
+ Miso.CSS: relativeAlignBottom :: MisoString -> Style
+ Miso.CSS: relativeAlignInlineEnd :: MisoString -> Style
+ Miso.CSS: relativeAlignInlineStart :: MisoString -> Style
+ Miso.CSS: relativeAlignLeft :: MisoString -> Style
+ Miso.CSS: relativeAlignRight :: MisoString -> Style
+ Miso.CSS: relativeAlignTop :: MisoString -> Style
+ Miso.CSS: relativeBottomOf :: MisoString -> Style
+ Miso.CSS: relativeCenter :: MisoString -> Style
+ Miso.CSS: relativeId :: MisoString -> Style
+ Miso.CSS: relativeInlineEndOf :: MisoString -> Style
+ Miso.CSS: relativeInlineStartOf :: MisoString -> Style
+ Miso.CSS: relativeLayoutOnce :: MisoString -> Style
+ Miso.CSS: relativeLeftOf :: MisoString -> Style
+ Miso.CSS: relativeRightOf :: MisoString -> Style
+ Miso.CSS: relativeTopOf :: MisoString -> Style
+ Miso.CSS: rem :: Double -> MisoString
+ Miso.CSS: renderStyleSheet :: StyleSheet -> MisoString
+ Miso.CSS: right :: MisoString -> Style
+ Miso.CSS: rowGap :: MisoString -> Style
+ Miso.CSS: rpx :: Double -> MisoString
+ Miso.CSS: s :: Double -> MisoString
+ Miso.CSS: selector_ :: MisoString -> [Style] -> Styles
+ Miso.CSS: sheet_ :: [Styles] -> StyleSheet
+ Miso.CSS: stroke :: MisoString -> Style
+ Miso.CSS: strokeWidth :: MisoString -> Style
+ Miso.CSS: styleInline_ :: MisoString -> Attribute action
+ Miso.CSS: style_ :: [Style] -> Attribute action
+ Miso.CSS: textAlign :: MisoString -> Style
+ Miso.CSS: textDecoration :: MisoString -> Style
+ Miso.CSS: textIndent :: MisoString -> Style
+ Miso.CSS: textOverflow :: MisoString -> Style
+ Miso.CSS: textShadow :: MisoString -> Style
+ Miso.CSS: textStroke :: MisoString -> Style
+ Miso.CSS: textStrokeColor :: Color -> Style
+ Miso.CSS: textStrokeWidth :: MisoString -> Style
+ Miso.CSS: top :: MisoString -> Style
+ Miso.CSS: transform :: MisoString -> Style
+ Miso.CSS: transformOrigin :: MisoString -> Style
+ Miso.CSS: transition :: MisoString -> Style
+ Miso.CSS: transitionDelay :: MisoString -> Style
+ Miso.CSS: transitionDuration :: MisoString -> Style
+ Miso.CSS: transitionProperty :: MisoString -> Style
+ Miso.CSS: transitionTimingFunction :: MisoString -> Style
+ Miso.CSS: turn :: Double -> MisoString
+ Miso.CSS: url :: MisoString -> MisoString
+ Miso.CSS: verticalAlign :: MisoString -> Style
+ Miso.CSS: vh :: Double -> MisoString
+ Miso.CSS: visibility :: MisoString -> Style
+ Miso.CSS: vw :: Double -> MisoString
+ Miso.CSS: whiteSpace :: MisoString -> Style
+ Miso.CSS: width :: MisoString -> Style
+ Miso.CSS: wordBreak :: MisoString -> Style
+ Miso.CSS: xAutoFontSize :: MisoString -> Style
+ Miso.CSS: xAutoFontSizePresetSizes :: MisoString -> Style
+ Miso.CSS: xHandleColor :: Color -> Style
+ Miso.CSS: xHandleSize :: MisoString -> Style
+ Miso.CSS: zIndex :: MisoString -> Style
+ Miso.CSS.Color: HSL :: Int -> Int -> Int -> Color
+ Miso.CSS.Color: HSLA :: Int -> Int -> Int -> Double -> Color
+ Miso.CSS.Color: Hex :: MisoString -> Color
+ Miso.CSS.Color: OKLCH :: Double -> Double -> Double -> Color
+ Miso.CSS.Color: OKLCHA :: Double -> Double -> Double -> Double -> Color
+ Miso.CSS.Color: RGB :: Int -> Int -> Int -> Color
+ Miso.CSS.Color: RGBA :: Int -> Int -> Int -> Double -> Color
+ Miso.CSS.Color: aliceblue :: Color
+ Miso.CSS.Color: antiquewhite :: Color
+ Miso.CSS.Color: aqua :: Color
+ Miso.CSS.Color: aquamarine :: Color
+ Miso.CSS.Color: azure :: Color
+ Miso.CSS.Color: beige :: Color
+ Miso.CSS.Color: bisque :: Color
+ Miso.CSS.Color: black :: Color
+ Miso.CSS.Color: blanchedalmond :: Color
+ Miso.CSS.Color: blue :: Color
+ Miso.CSS.Color: blueviolet :: Color
+ Miso.CSS.Color: brown :: Color
+ Miso.CSS.Color: burlywood :: Color
+ Miso.CSS.Color: cadetblue :: Color
+ Miso.CSS.Color: chartreuse :: Color
+ Miso.CSS.Color: chocolate :: Color
+ Miso.CSS.Color: coral :: Color
+ Miso.CSS.Color: cornflowerblue :: Color
+ Miso.CSS.Color: cornsilk :: Color
+ Miso.CSS.Color: crimson :: Color
+ Miso.CSS.Color: cyan :: Color
+ Miso.CSS.Color: darkblue :: Color
+ Miso.CSS.Color: darkcyan :: Color
+ Miso.CSS.Color: darkgoldenrod :: Color
+ Miso.CSS.Color: darkgray :: Color
+ Miso.CSS.Color: darkgreen :: Color
+ Miso.CSS.Color: darkgrey :: Color
+ Miso.CSS.Color: darkkhaki :: Color
+ Miso.CSS.Color: darkmagenta :: Color
+ Miso.CSS.Color: darkolivegreen :: Color
+ Miso.CSS.Color: darkorange :: Color
+ Miso.CSS.Color: darkorchid :: Color
+ Miso.CSS.Color: darkred :: Color
+ Miso.CSS.Color: darksalmon :: Color
+ Miso.CSS.Color: darkseagreen :: Color
+ Miso.CSS.Color: darkslateblue :: Color
+ Miso.CSS.Color: darkslategray :: Color
+ Miso.CSS.Color: darkslategrey :: Color
+ Miso.CSS.Color: darkturquoise :: Color
+ Miso.CSS.Color: darkviolet :: Color
+ Miso.CSS.Color: data Color
+ Miso.CSS.Color: deeppink :: Color
+ Miso.CSS.Color: deepskyblue :: Color
+ Miso.CSS.Color: dimgray :: Color
+ Miso.CSS.Color: dimgrey :: Color
+ Miso.CSS.Color: dodgerblue :: Color
+ Miso.CSS.Color: firebrick :: Color
+ Miso.CSS.Color: floralwhite :: Color
+ Miso.CSS.Color: forestgreen :: Color
+ Miso.CSS.Color: fuchsia :: Color
+ Miso.CSS.Color: gainsboro :: Color
+ Miso.CSS.Color: ghostwhite :: Color
+ Miso.CSS.Color: gold :: Color
+ Miso.CSS.Color: goldenrod :: Color
+ Miso.CSS.Color: gray :: Color
+ Miso.CSS.Color: green :: Color
+ Miso.CSS.Color: greenyellow :: Color
+ Miso.CSS.Color: grey :: Color
+ Miso.CSS.Color: hex :: MisoString -> Color
+ Miso.CSS.Color: honeydew :: Color
+ Miso.CSS.Color: hotpink :: Color
+ Miso.CSS.Color: hsl :: Int -> Int -> Int -> Color
+ Miso.CSS.Color: hsla :: Int -> Int -> Int -> Double -> Color
+ Miso.CSS.Color: indianred :: Color
+ Miso.CSS.Color: indigo :: Color
+ Miso.CSS.Color: instance GHC.Classes.Eq Miso.CSS.Color.Color
+ Miso.CSS.Color: instance GHC.Show.Show Miso.CSS.Color.Color
+ Miso.CSS.Color: instance GHC.TypeLits.KnownSymbol color => GHC.OverloadedLabels.IsLabel color Miso.CSS.Color.Color
+ Miso.CSS.Color: instance GHC.TypeLits.KnownSymbol hex => GHC.OverloadedLabels.IsLabel hex Miso.String.MisoString
+ Miso.CSS.Color: instance Miso.DSL.ToArgs Miso.CSS.Color.Color
+ Miso.CSS.Color: instance Miso.DSL.ToJSVal Miso.CSS.Color.Color
+ Miso.CSS.Color: ivory :: Color
+ Miso.CSS.Color: khaki :: Color
+ Miso.CSS.Color: lavender :: Color
+ Miso.CSS.Color: lavenderblush :: Color
+ Miso.CSS.Color: lawngreen :: Color
+ Miso.CSS.Color: lemonchiffon :: Color
+ Miso.CSS.Color: lightblue :: Color
+ Miso.CSS.Color: lightcoral :: Color
+ Miso.CSS.Color: lightcyan :: Color
+ Miso.CSS.Color: lightgoldenrodyellow :: Color
+ Miso.CSS.Color: lightgray :: Color
+ Miso.CSS.Color: lightgreen :: Color
+ Miso.CSS.Color: lightgrey :: Color
+ Miso.CSS.Color: lightpink :: Color
+ Miso.CSS.Color: lightsalmon :: Color
+ Miso.CSS.Color: lightseagreen :: Color
+ Miso.CSS.Color: lightskyblue :: Color
+ Miso.CSS.Color: lightslategray :: Color
+ Miso.CSS.Color: lightslategrey :: Color
+ Miso.CSS.Color: lightsteelblue :: Color
+ Miso.CSS.Color: lightyellow :: Color
+ Miso.CSS.Color: lime :: Color
+ Miso.CSS.Color: limegreen :: Color
+ Miso.CSS.Color: linen :: Color
+ Miso.CSS.Color: magenta :: Color
+ Miso.CSS.Color: maroon :: Color
+ Miso.CSS.Color: mediumaquamarine :: Color
+ Miso.CSS.Color: mediumblue :: Color
+ Miso.CSS.Color: mediumorchid :: Color
+ Miso.CSS.Color: mediumpurple :: Color
+ Miso.CSS.Color: mediumseagreen :: Color
+ Miso.CSS.Color: mediumslateblue :: Color
+ Miso.CSS.Color: mediumspringgreen :: Color
+ Miso.CSS.Color: mediumturquoise :: Color
+ Miso.CSS.Color: mediumvioletred :: Color
+ Miso.CSS.Color: midnightblue :: Color
+ Miso.CSS.Color: mintcream :: Color
+ Miso.CSS.Color: mistyrose :: Color
+ Miso.CSS.Color: moccasin :: Color
+ Miso.CSS.Color: navajowhite :: Color
+ Miso.CSS.Color: navy :: Color
+ Miso.CSS.Color: oklch :: Double -> Double -> Double -> Color
+ Miso.CSS.Color: oklcha :: Double -> Double -> Double -> Double -> Color
+ Miso.CSS.Color: oldlace :: Color
+ Miso.CSS.Color: olive :: Color
+ Miso.CSS.Color: olivedrab :: Color
+ Miso.CSS.Color: orange :: Color
+ Miso.CSS.Color: orangered :: Color
+ Miso.CSS.Color: orchid :: Color
+ Miso.CSS.Color: palegoldenrod :: Color
+ Miso.CSS.Color: palegreen :: Color
+ Miso.CSS.Color: paleturquoise :: Color
+ Miso.CSS.Color: palevioletred :: Color
+ Miso.CSS.Color: papayawhip :: Color
+ Miso.CSS.Color: peachpuff :: Color
+ Miso.CSS.Color: peru :: Color
+ Miso.CSS.Color: pink :: Color
+ Miso.CSS.Color: plum :: Color
+ Miso.CSS.Color: powderblue :: Color
+ Miso.CSS.Color: purple :: Color
+ Miso.CSS.Color: red :: Color
+ Miso.CSS.Color: renderColor :: Color -> MisoString
+ Miso.CSS.Color: rgb :: Int -> Int -> Int -> Color
+ Miso.CSS.Color: rgba :: Int -> Int -> Int -> Double -> Color
+ Miso.CSS.Color: rosybrown :: Color
+ Miso.CSS.Color: royalblue :: Color
+ Miso.CSS.Color: saddlebrown :: Color
+ Miso.CSS.Color: salmon :: Color
+ Miso.CSS.Color: sandybrown :: Color
+ Miso.CSS.Color: seagreen :: Color
+ Miso.CSS.Color: seashell :: Color
+ Miso.CSS.Color: sienna :: Color
+ Miso.CSS.Color: silver :: Color
+ Miso.CSS.Color: skyblue :: Color
+ Miso.CSS.Color: slateblue :: Color
+ Miso.CSS.Color: slategray :: Color
+ Miso.CSS.Color: slategrey :: Color
+ Miso.CSS.Color: snow :: Color
+ Miso.CSS.Color: springgreen :: Color
+ Miso.CSS.Color: steelblue :: Color
+ Miso.CSS.Color: tan :: Color
+ Miso.CSS.Color: teal :: Color
+ Miso.CSS.Color: thistle :: Color
+ Miso.CSS.Color: tomato :: Color
+ Miso.CSS.Color: transparent :: Color
+ Miso.CSS.Color: turquoise :: Color
+ Miso.CSS.Color: var :: MisoString -> Color
+ Miso.CSS.Color: violet :: Color
+ Miso.CSS.Color: wheat :: Color
+ Miso.CSS.Color: white :: Color
+ Miso.CSS.Color: whitesmoke :: Color
+ Miso.CSS.Color: yellow :: Color
+ Miso.CSS.Color: yellowgreen :: Color
+ Miso.CSS.Types: KeyFrame :: MisoString -> [(MisoString, [Style])] -> Styles
+ Miso.CSS.Types: Media :: MisoString -> [(MisoString, [Style])] -> Styles
+ Miso.CSS.Types: StyleSheet :: [Styles] -> StyleSheet
+ Miso.CSS.Types: Styles :: (MisoString, [Style]) -> Styles
+ Miso.CSS.Types: [getStyleSheet] :: StyleSheet -> [Styles]
+ Miso.CSS.Types: data Styles
+ Miso.CSS.Types: instance GHC.Classes.Eq Miso.CSS.Types.StyleSheet
+ Miso.CSS.Types: instance GHC.Classes.Eq Miso.CSS.Types.Styles
+ Miso.CSS.Types: instance GHC.Show.Show Miso.CSS.Types.StyleSheet
+ Miso.CSS.Types: instance GHC.Show.Show Miso.CSS.Types.Styles
+ Miso.CSS.Types: newtype StyleSheet
+ Miso.CSS.Types: type Style = (MisoString, MisoString)
+ Miso.Canvas: ColorArg :: Color -> StyleArg
+ Miso.Canvas: Copy :: CompositeOperation
+ Miso.Canvas: DestinationAtop :: CompositeOperation
+ Miso.Canvas: DestinationIn :: CompositeOperation
+ Miso.Canvas: DestinationOut :: CompositeOperation
+ Miso.Canvas: DestinationOver :: CompositeOperation
+ Miso.Canvas: Gradient :: JSVal -> Gradient
+ Miso.Canvas: GradientArg :: Gradient -> StyleArg
+ Miso.Canvas: ImageData :: JSVal -> ImageData
+ Miso.Canvas: Inherit :: DirectionType
+ Miso.Canvas: LTR :: DirectionType
+ Miso.Canvas: Lighter :: CompositeOperation
+ Miso.Canvas: LineCapButt :: LineCapType
+ Miso.Canvas: LineCapRound :: LineCapType
+ Miso.Canvas: LineCapSquare :: LineCapType
+ Miso.Canvas: LineJoinBevel :: LineJoinType
+ Miso.Canvas: LineJoinMiter :: LineJoinType
+ Miso.Canvas: LineJoinRound :: LineJoinType
+ Miso.Canvas: NoRepeat :: PatternType
+ Miso.Canvas: Pattern :: JSVal -> Pattern
+ Miso.Canvas: PatternArg :: Pattern -> StyleArg
+ Miso.Canvas: RTL :: DirectionType
+ Miso.Canvas: Repeat :: PatternType
+ Miso.Canvas: RepeatX :: PatternType
+ Miso.Canvas: RepeatY :: PatternType
+ Miso.Canvas: SourceAtop :: CompositeOperation
+ Miso.Canvas: SourceIn :: CompositeOperation
+ Miso.Canvas: SourceOut :: CompositeOperation
+ Miso.Canvas: SourceOver :: CompositeOperation
+ Miso.Canvas: TextAlignCenter :: TextAlignType
+ Miso.Canvas: TextAlignEnd :: TextAlignType
+ Miso.Canvas: TextAlignLeft :: TextAlignType
+ Miso.Canvas: TextAlignRight :: TextAlignType
+ Miso.Canvas: TextAlignStart :: TextAlignType
+ Miso.Canvas: TextBaselineAlphabetic :: TextBaselineType
+ Miso.Canvas: TextBaselineBottom :: TextBaselineType
+ Miso.Canvas: TextBaselineHanging :: TextBaselineType
+ Miso.Canvas: TextBaselineIdeographic :: TextBaselineType
+ Miso.Canvas: TextBaselineMiddle :: TextBaselineType
+ Miso.Canvas: TextBaselineTop :: TextBaselineType
+ Miso.Canvas: Xor :: CompositeOperation
+ Miso.Canvas: addColorStop :: (Double, Color) -> Gradient -> Canvas ()
+ Miso.Canvas: arc :: (Double, Double, Double, Double, Double) -> Canvas ()
+ Miso.Canvas: arcTo :: (Double, Double, Double, Double, Double) -> Canvas ()
+ Miso.Canvas: beginPath :: () -> Canvas ()
+ Miso.Canvas: bezierCurveTo :: (Double, Double, Double, Double, Double, Double) -> Canvas ()
+ Miso.Canvas: canvas :: forall model action canvasState. (FromJSVal canvasState, ToJSVal canvasState) => [Attribute action] -> (DOMRef -> Canvas canvasState) -> (canvasState -> Canvas ()) -> View model action
+ Miso.Canvas: canvas_ :: forall model action canvasState. (FromJSVal canvasState, ToJSVal canvasState) => [Attribute action] -> (DOMRef -> IO canvasState) -> (canvasState -> IO ()) -> View model action
+ Miso.Canvas: clearRect :: (Double, Double, Double, Double) -> Canvas ()
+ Miso.Canvas: clip :: () -> Canvas ()
+ Miso.Canvas: closePath :: () -> Canvas ()
+ Miso.Canvas: color :: Color -> StyleArg
+ Miso.Canvas: createImageData :: (Double, Double) -> Canvas ImageData
+ Miso.Canvas: createLinearGradient :: (Double, Double, Double, Double) -> Canvas Gradient
+ Miso.Canvas: createPattern :: (Image, PatternType) -> Canvas Pattern
+ Miso.Canvas: createRadialGradient :: (Double, Double, Double, Double, Double, Double) -> Canvas Gradient
+ Miso.Canvas: data CompositeOperation
+ Miso.Canvas: data DirectionType
+ Miso.Canvas: data LineCapType
+ Miso.Canvas: data LineJoinType
+ Miso.Canvas: data PatternType
+ Miso.Canvas: data StyleArg
+ Miso.Canvas: data TextAlignType
+ Miso.Canvas: data TextBaselineType
+ Miso.Canvas: direction :: DirectionType -> Canvas ()
+ Miso.Canvas: drawImage :: (Image, Double, Double) -> Canvas ()
+ Miso.Canvas: drawImage' :: (Image, Double, Double, Double, Double) -> Canvas ()
+ Miso.Canvas: fill :: () -> Canvas ()
+ Miso.Canvas: fillRect :: (Double, Double, Double, Double) -> Canvas ()
+ Miso.Canvas: fillStyle :: StyleArg -> Canvas ()
+ Miso.Canvas: fillText :: (MisoString, Double, Double) -> Canvas ()
+ Miso.Canvas: font :: MisoString -> Canvas ()
+ Miso.Canvas: getImageData :: (Double, Double, Double, Double) -> Canvas ImageData
+ Miso.Canvas: globalAlpha :: Double -> Canvas ()
+ Miso.Canvas: globalCompositeOperation :: CompositeOperation -> Canvas ()
+ Miso.Canvas: gradient :: Gradient -> StyleArg
+ Miso.Canvas: height :: ImageData -> Canvas Double
+ Miso.Canvas: instance GHC.Classes.Eq Miso.Canvas.CompositeOperation
+ Miso.Canvas: instance GHC.Classes.Eq Miso.Canvas.DirectionType
+ Miso.Canvas: instance GHC.Classes.Eq Miso.Canvas.LineCapType
+ Miso.Canvas: instance GHC.Classes.Eq Miso.Canvas.LineJoinType
+ Miso.Canvas: instance GHC.Classes.Eq Miso.Canvas.TextAlignType
+ Miso.Canvas: instance GHC.Classes.Eq Miso.Canvas.TextBaselineType
+ Miso.Canvas: instance GHC.Show.Show Miso.Canvas.CompositeOperation
+ Miso.Canvas: instance GHC.Show.Show Miso.Canvas.DirectionType
+ Miso.Canvas: instance GHC.Show.Show Miso.Canvas.LineCapType
+ Miso.Canvas: instance GHC.Show.Show Miso.Canvas.LineJoinType
+ Miso.Canvas: instance GHC.Show.Show Miso.Canvas.TextAlignType
+ Miso.Canvas: instance GHC.Show.Show Miso.Canvas.TextBaselineType
+ Miso.Canvas: instance Miso.DSL.FromJSVal Miso.Canvas.Gradient
+ Miso.Canvas: instance Miso.DSL.FromJSVal Miso.Canvas.ImageData
+ Miso.Canvas: instance Miso.DSL.FromJSVal Miso.Canvas.Pattern
+ Miso.Canvas: instance Miso.DSL.FromJSVal Miso.Canvas.PatternType
+ Miso.Canvas: instance Miso.DSL.ToArgs Miso.Canvas.CompositeOperation
+ Miso.Canvas: instance Miso.DSL.ToArgs Miso.Canvas.DirectionType
+ Miso.Canvas: instance Miso.DSL.ToArgs Miso.Canvas.Gradient
+ Miso.Canvas: instance Miso.DSL.ToArgs Miso.Canvas.ImageData
+ Miso.Canvas: instance Miso.DSL.ToArgs Miso.Canvas.LineCapType
+ Miso.Canvas: instance Miso.DSL.ToArgs Miso.Canvas.LineJoinType
+ Miso.Canvas: instance Miso.DSL.ToArgs Miso.Canvas.StyleArg
+ Miso.Canvas: instance Miso.DSL.ToArgs Miso.Canvas.TextAlignType
+ Miso.Canvas: instance Miso.DSL.ToArgs Miso.Canvas.TextBaselineType
+ Miso.Canvas: instance Miso.DSL.ToJSVal Miso.Canvas.CompositeOperation
+ Miso.Canvas: instance Miso.DSL.ToJSVal Miso.Canvas.DirectionType
+ Miso.Canvas: instance Miso.DSL.ToJSVal Miso.Canvas.Gradient
+ Miso.Canvas: instance Miso.DSL.ToJSVal Miso.Canvas.ImageData
+ Miso.Canvas: instance Miso.DSL.ToJSVal Miso.Canvas.LineCapType
+ Miso.Canvas: instance Miso.DSL.ToJSVal Miso.Canvas.LineJoinType
+ Miso.Canvas: instance Miso.DSL.ToJSVal Miso.Canvas.Pattern
+ Miso.Canvas: instance Miso.DSL.ToJSVal Miso.Canvas.PatternType
+ Miso.Canvas: instance Miso.DSL.ToJSVal Miso.Canvas.StyleArg
+ Miso.Canvas: instance Miso.DSL.ToJSVal Miso.Canvas.TextAlignType
+ Miso.Canvas: instance Miso.DSL.ToJSVal Miso.Canvas.TextBaselineType
+ Miso.Canvas: instance Miso.DSL.ToObject Miso.Canvas.ImageData
+ Miso.Canvas: lineCap :: LineCapType -> Canvas ()
+ Miso.Canvas: lineJoin :: LineJoinType -> Canvas ()
+ Miso.Canvas: lineTo :: Coord -> Canvas ()
+ Miso.Canvas: lineWidth :: Double -> Canvas ()
+ Miso.Canvas: miterLimit :: Double -> Canvas ()
+ Miso.Canvas: moveTo :: Coord -> Canvas ()
+ Miso.Canvas: newtype Gradient
+ Miso.Canvas: newtype ImageData
+ Miso.Canvas: newtype Pattern
+ Miso.Canvas: pattern_ :: Pattern -> StyleArg
+ Miso.Canvas: putImageData :: (ImageData, Double, Double) -> Canvas ()
+ Miso.Canvas: quadraticCurveTo :: (Double, Double, Double, Double) -> Canvas ()
+ Miso.Canvas: rect :: (Double, Double, Double, Double) -> Canvas ()
+ Miso.Canvas: restore :: () -> Canvas ()
+ Miso.Canvas: rotate :: Double -> Canvas ()
+ Miso.Canvas: save :: () -> Canvas ()
+ Miso.Canvas: scale :: (Double, Double) -> Canvas ()
+ Miso.Canvas: set :: ToArgs args => MisoString -> args -> Canvas ()
+ Miso.Canvas: setImageData :: (ImageData, Int, Double) -> Canvas ()
+ Miso.Canvas: setTransform :: (Double, Double, Double, Double, Double, Double) -> Canvas ()
+ Miso.Canvas: shadowBlur :: Double -> Canvas ()
+ Miso.Canvas: shadowColor :: Color -> Canvas ()
+ Miso.Canvas: shadowOffsetX :: Double -> Canvas ()
+ Miso.Canvas: shadowOffsetY :: Double -> Canvas ()
+ Miso.Canvas: stroke :: () -> Canvas ()
+ Miso.Canvas: strokeRect :: (Double, Double, Double, Double) -> Canvas ()
+ Miso.Canvas: strokeStyle :: StyleArg -> Canvas ()
+ Miso.Canvas: strokeText :: (MisoString, Double, Double) -> Canvas ()
+ Miso.Canvas: textAlign :: TextAlignType -> Canvas ()
+ Miso.Canvas: textBaseline :: TextBaselineType -> Canvas ()
+ Miso.Canvas: transform :: (Double, Double, Double, Double, Double, Double) -> Canvas ()
+ Miso.Canvas: translate :: Coord -> Canvas ()
+ Miso.Canvas: type Canvas a = ReaderT CanvasContext2D IO a
+ Miso.Canvas: type CanvasContext2D = JSVal
+ Miso.Canvas: type Coord = (Double, Double)
+ Miso.Canvas: width :: ImageData -> Canvas Double
+ Miso.Concurrent: Waiter :: IO () -> IO () -> Waiter
+ Miso.Concurrent: [notify] :: Waiter -> IO ()
+ Miso.Concurrent: [wait] :: Waiter -> IO ()
+ Miso.Concurrent: data Waiter
+ Miso.Concurrent: oneshot :: IO Waiter
+ Miso.Concurrent: waiter :: IO Waiter
+ Miso.DSL: (!!) :: ToObject object => object -> Int -> IO JSVal
+ Miso.DSL: (!) :: ToObject o => o -> MisoString -> IO JSVal
+ Miso.DSL: (#) :: (ToObject object, ToArgs args) => object -> MisoString -> args -> IO JSVal
+ Miso.DSL: ($dmfromJSVal) :: (FromJSVal a, Generic a, GFromJSVal (Rep a)) => JSVal -> IO (Maybe a)
+ Miso.DSL: ($dmtoJSVal) :: (ToJSVal a, Generic a, GToJSVal (Rep a)) => a -> IO JSVal
+ Miso.DSL: ($dmtoObject) :: (ToObject a, Generic a, GToJSVal (Rep a)) => a -> IO Object
+ Miso.DSL: (<##) :: (ToObject o, ToJSVal v) => o -> Int -> v -> IO ()
+ Miso.DSL: Function :: JSVal -> Function
+ Miso.DSL: Object :: JSVal -> Object
+ Miso.DSL: [unFunction] :: Function -> JSVal
+ Miso.DSL: [unObject] :: Object -> JSVal
+ Miso.DSL: apply :: (FromJSVal a, ToArgs args) => Function -> args -> IO a
+ Miso.DSL: asyncCallback :: IO () -> IO JSVal
+ Miso.DSL: asyncCallback1 :: (JSVal -> IO ()) -> IO JSVal
+ Miso.DSL: asyncCallback2 :: (JSVal -> JSVal -> IO ()) -> IO JSVal
+ Miso.DSL: asyncCallback3 :: (JSVal -> JSVal -> JSVal -> IO ()) -> IO JSVal
+ Miso.DSL: call :: (ToObject obj, ToObject this, ToArgs args) => obj -> this -> args -> IO JSVal
+ Miso.DSL: cancelAnimationFrame :: Int -> IO ()
+ Miso.DSL: class FromJSVal a
+ Miso.DSL: class GFromJSVal (f :: Type -> Type)
+ Miso.DSL: class GToJSVal (f :: Type -> Type)
+ Miso.DSL: class ToArgs args
+ Miso.DSL: class ToJSVal a
+ Miso.DSL: class ToObject a
+ Miso.DSL: create :: IO Object
+ Miso.DSL: createWith :: ToJSVal val => [(MisoString, val)] -> IO Object
+ Miso.DSL: data JSVal
+ Miso.DSL: eval :: MisoString -> IO JSVal
+ Miso.DSL: freeFunction :: Function -> IO ()
+ Miso.DSL: fromJSVal :: FromJSVal a => JSVal -> IO (Maybe a)
+ Miso.DSL: fromJSValUnchecked :: FromJSVal a => JSVal -> IO a
+ Miso.DSL: gFromJSVal :: GFromJSVal f => Object -> IO (Maybe (f a))
+ Miso.DSL: gToJSVal :: GToJSVal f => f a -> Object -> IO ()
+ Miso.DSL: getProp :: ToObject o => MisoString -> o -> IO JSVal
+ Miso.DSL: global :: JSVal
+ Miso.DSL: infixr 1 <##
+ Miso.DSL: infixr 2 #
+ Miso.DSL: instance ((TypeError ...), Miso.DSL.GFromJSVal a, Miso.DSL.GFromJSVal b) => Miso.DSL.GFromJSVal (a GHC.Generics.:+: b)
+ Miso.DSL: instance ((TypeError ...), Miso.DSL.GToJSVal a, Miso.DSL.GToJSVal b) => Miso.DSL.GToJSVal (a GHC.Generics.:+: b)
+ Miso.DSL: instance (Miso.DSL.FromJSVal a, GHC.Generics.Selector s) => Miso.DSL.GFromJSVal (GHC.Generics.S1 s (GHC.Generics.K1 i a))
+ Miso.DSL: instance (Miso.DSL.FromJSVal a, Miso.DSL.FromJSVal b) => Miso.DSL.FromJSVal (a, b)
+ Miso.DSL: instance (Miso.DSL.FromJSVal a, Miso.DSL.FromJSVal b, Miso.DSL.FromJSVal c) => Miso.DSL.FromJSVal (a, b, c)
+ Miso.DSL: instance (Miso.DSL.FromJSVal a, Miso.DSL.FromJSVal b, Miso.DSL.FromJSVal c, Miso.DSL.FromJSVal d) => Miso.DSL.FromJSVal (a, b, c, d)
+ Miso.DSL: instance (Miso.DSL.FromJSVal a, Miso.DSL.FromJSVal b, Miso.DSL.FromJSVal c, Miso.DSL.FromJSVal d, Miso.DSL.FromJSVal e) => Miso.DSL.FromJSVal (a, b, c, d, e)
+ Miso.DSL: instance (Miso.DSL.FromJSVal a, Miso.DSL.FromJSVal b, Miso.DSL.FromJSVal c, Miso.DSL.FromJSVal d, Miso.DSL.FromJSVal e, Miso.DSL.FromJSVal f) => Miso.DSL.FromJSVal (a, b, c, d, e, f)
+ Miso.DSL: instance (Miso.DSL.FromJSVal a, Miso.DSL.FromJSVal b, Miso.DSL.FromJSVal c, Miso.DSL.FromJSVal d, Miso.DSL.FromJSVal e, Miso.DSL.FromJSVal f, Miso.DSL.FromJSVal g) => Miso.DSL.FromJSVal (a, b, c, d, e, f, g)
+ Miso.DSL: instance (Miso.DSL.FromJSVal a, Miso.DSL.FromJSVal b, Miso.DSL.FromJSVal c, Miso.DSL.FromJSVal d, Miso.DSL.FromJSVal e, Miso.DSL.FromJSVal f, Miso.DSL.FromJSVal g, Miso.DSL.FromJSVal h) => Miso.DSL.FromJSVal (a, b, c, d, e, f, g, h)
+ Miso.DSL: instance (Miso.DSL.GFromJSVal a, Miso.DSL.GFromJSVal b) => Miso.DSL.GFromJSVal (a GHC.Generics.:*: b)
+ Miso.DSL: instance (Miso.DSL.GToJSVal a, Miso.DSL.GToJSVal b) => Miso.DSL.GToJSVal (a GHC.Generics.:*: b)
+ Miso.DSL: instance (Miso.DSL.ToJSVal a, GHC.Generics.Selector s) => Miso.DSL.GToJSVal (GHC.Generics.S1 s (GHC.Generics.K1 i a))
+ Miso.DSL: instance (Miso.DSL.ToJSVal a, Miso.DSL.ToJSVal b) => Miso.DSL.ToJSVal (a, b)
+ Miso.DSL: instance (Miso.DSL.ToJSVal a, Miso.DSL.ToJSVal b, Miso.DSL.ToJSVal c) => Miso.DSL.ToJSVal (a, b, c)
+ Miso.DSL: instance (Miso.DSL.ToJSVal a, Miso.DSL.ToJSVal b, Miso.DSL.ToJSVal c, Miso.DSL.ToJSVal d) => Miso.DSL.ToJSVal (a, b, c, d)
+ Miso.DSL: instance (Miso.DSL.ToJSVal a, Miso.DSL.ToJSVal b, Miso.DSL.ToJSVal c, Miso.DSL.ToJSVal d, Miso.DSL.ToJSVal e) => Miso.DSL.ToJSVal (a, b, c, d, e)
+ Miso.DSL: instance (Miso.DSL.ToJSVal a, Miso.DSL.ToJSVal b, Miso.DSL.ToJSVal c, Miso.DSL.ToJSVal d, Miso.DSL.ToJSVal e, Miso.DSL.ToJSVal f) => Miso.DSL.ToJSVal (a, b, c, d, e, f)
+ Miso.DSL: instance (Miso.DSL.ToJSVal arg1, Miso.DSL.ToJSVal arg2) => Miso.DSL.ToArgs (arg1, arg2)
+ Miso.DSL: instance (Miso.DSL.ToJSVal arg1, Miso.DSL.ToJSVal arg2, Miso.DSL.ToJSVal arg3) => Miso.DSL.ToArgs (arg1, arg2, arg3)
+ Miso.DSL: instance (Miso.DSL.ToJSVal arg1, Miso.DSL.ToJSVal arg2, Miso.DSL.ToJSVal arg3, Miso.DSL.ToJSVal arg4) => Miso.DSL.ToArgs (arg1, arg2, arg3, arg4)
+ Miso.DSL: instance (Miso.DSL.ToJSVal arg1, Miso.DSL.ToJSVal arg2, Miso.DSL.ToJSVal arg3, Miso.DSL.ToJSVal arg4, Miso.DSL.ToJSVal arg5) => Miso.DSL.ToArgs (arg1, arg2, arg3, arg4, arg5)
+ Miso.DSL: instance (Miso.DSL.ToJSVal arg1, Miso.DSL.ToJSVal arg2, Miso.DSL.ToJSVal arg3, Miso.DSL.ToJSVal arg4, Miso.DSL.ToJSVal arg5, Miso.DSL.ToJSVal arg6) => Miso.DSL.ToArgs (arg1, arg2, arg3, arg4, arg5, arg6)
+ Miso.DSL: instance GHC.Classes.Eq Miso.DSL.Function
+ Miso.DSL: instance GHC.Classes.Eq Miso.DSL.Object
+ Miso.DSL: instance Miso.DSL.FromJSVal ()
+ Miso.DSL: instance Miso.DSL.FromJSVal Data.Text.Internal.Text
+ Miso.DSL: instance Miso.DSL.FromJSVal GHC.Types.Bool
+ Miso.DSL: instance Miso.DSL.FromJSVal GHC.Types.Char
+ Miso.DSL: instance Miso.DSL.FromJSVal GHC.Types.Double
+ Miso.DSL: instance Miso.DSL.FromJSVal GHC.Types.Float
+ Miso.DSL: instance Miso.DSL.FromJSVal GHC.Types.Int
+ Miso.DSL: instance Miso.DSL.FromJSVal Miso.DSL.FFI.JSVal
+ Miso.DSL: instance Miso.DSL.FromJSVal Miso.DSL.Function
+ Miso.DSL: instance Miso.DSL.FromJSVal Miso.DSL.Object
+ Miso.DSL: instance Miso.DSL.FromJSVal Miso.JSON.Types.Value
+ Miso.DSL: instance Miso.DSL.FromJSVal [GHC.Types.Char]
+ Miso.DSL: instance Miso.DSL.FromJSVal a => Miso.DSL.FromJSVal (Data.Map.Internal.Map Miso.String.MisoString a)
+ Miso.DSL: instance Miso.DSL.FromJSVal a => Miso.DSL.FromJSVal (GHC.Maybe.Maybe a)
+ Miso.DSL: instance Miso.DSL.FromJSVal a => Miso.DSL.FromJSVal [a]
+ Miso.DSL: instance Miso.DSL.GFromJSVal GHC.Generics.U1
+ Miso.DSL: instance Miso.DSL.GFromJSVal GHC.Generics.V1
+ Miso.DSL: instance Miso.DSL.GFromJSVal a => Miso.DSL.GFromJSVal (GHC.Generics.C1 i a)
+ Miso.DSL: instance Miso.DSL.GFromJSVal a => Miso.DSL.GFromJSVal (GHC.Generics.D1 i a)
+ Miso.DSL: instance Miso.DSL.GToJSVal GHC.Generics.U1
+ Miso.DSL: instance Miso.DSL.GToJSVal GHC.Generics.V1
+ Miso.DSL: instance Miso.DSL.GToJSVal a => Miso.DSL.GToJSVal (GHC.Generics.C1 i a)
+ Miso.DSL: instance Miso.DSL.GToJSVal a => Miso.DSL.GToJSVal (GHC.Generics.D1 i a)
+ Miso.DSL: instance Miso.DSL.ToArgs ()
+ Miso.DSL: instance Miso.DSL.ToArgs GHC.Types.Bool
+ Miso.DSL: instance Miso.DSL.ToArgs GHC.Types.Double
+ Miso.DSL: instance Miso.DSL.ToArgs GHC.Types.Int
+ Miso.DSL: instance Miso.DSL.ToArgs Miso.DSL.FFI.JSVal
+ Miso.DSL: instance Miso.DSL.ToArgs Miso.DSL.Function
+ Miso.DSL: instance Miso.DSL.ToArgs Miso.DSL.Object
+ Miso.DSL: instance Miso.DSL.ToArgs Miso.String.MisoString
+ Miso.DSL: instance Miso.DSL.ToArgs args => Miso.DSL.ToArgs (GHC.Maybe.Maybe args)
+ Miso.DSL: instance Miso.DSL.ToJSVal ()
+ Miso.DSL: instance Miso.DSL.ToJSVal Data.Text.Internal.Text
+ Miso.DSL: instance Miso.DSL.ToJSVal GHC.Types.Bool
+ Miso.DSL: instance Miso.DSL.ToJSVal GHC.Types.Char
+ Miso.DSL: instance Miso.DSL.ToJSVal GHC.Types.Double
+ Miso.DSL: instance Miso.DSL.ToJSVal GHC.Types.Float
+ Miso.DSL: instance Miso.DSL.ToJSVal GHC.Types.Int
+ Miso.DSL: instance Miso.DSL.ToJSVal Miso.DSL.FFI.JSVal
+ Miso.DSL: instance Miso.DSL.ToJSVal Miso.DSL.Function
+ Miso.DSL: instance Miso.DSL.ToJSVal Miso.DSL.Object
+ Miso.DSL: instance Miso.DSL.ToJSVal Miso.JSON.Types.Value
+ Miso.DSL: instance Miso.DSL.ToJSVal [GHC.Types.Char]
+ Miso.DSL: instance Miso.DSL.ToJSVal a => Miso.DSL.ToJSVal (Data.Map.Internal.Map Miso.String.MisoString a)
+ Miso.DSL: instance Miso.DSL.ToJSVal a => Miso.DSL.ToJSVal (GHC.Maybe.Maybe a)
+ Miso.DSL: instance Miso.DSL.ToJSVal a => Miso.DSL.ToJSVal (GHC.Types.IO a)
+ Miso.DSL: instance Miso.DSL.ToJSVal a => Miso.DSL.ToJSVal [a]
+ Miso.DSL: instance Miso.DSL.ToJSVal a => Miso.DSL.ToObject (Data.Map.Internal.Map Miso.String.MisoString a)
+ Miso.DSL: instance Miso.DSL.ToJSVal a => Miso.DSL.ToObject (GHC.Types.IO a)
+ Miso.DSL: instance Miso.DSL.ToJSVal arg => Miso.DSL.ToArgs [arg]
+ Miso.DSL: instance Miso.DSL.ToObject Miso.DSL.FFI.JSVal
+ Miso.DSL: instance Miso.DSL.ToObject Miso.DSL.Object
+ Miso.DSL: isNull :: ToJSVal val => val -> IO Bool
+ Miso.DSL: isUndefined :: ToJSVal val => val -> IO Bool
+ Miso.DSL: jsNull :: JSVal
+ Miso.DSL: jsg :: MisoString -> IO JSVal
+ Miso.DSL: jsg0 :: MisoString -> IO JSVal
+ Miso.DSL: jsg1 :: ToJSVal arg => MisoString -> arg -> IO JSVal
+ Miso.DSL: jsg2 :: (ToJSVal arg1, ToJSVal arg2) => MisoString -> arg1 -> arg2 -> IO JSVal
+ Miso.DSL: jsg3 :: (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3) => MisoString -> arg1 -> arg2 -> arg3 -> IO JSVal
+ Miso.DSL: jsg4 :: (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4) => MisoString -> arg1 -> arg2 -> arg3 -> arg4 -> IO JSVal
+ Miso.DSL: jsg5 :: (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4, ToJSVal arg5) => MisoString -> arg1 -> arg2 -> arg3 -> arg4 -> arg5 -> IO JSVal
+ Miso.DSL: jsgf :: ToArgs args => MisoString -> args -> IO JSVal
+ Miso.DSL: listProps :: Object -> IO [MisoString]
+ Miso.DSL: new :: (ToObject constructor, ToArgs args) => constructor -> args -> IO JSVal
+ Miso.DSL: newtype Function
+ Miso.DSL: newtype Object
+ Miso.DSL: requestAnimationFrame :: JSVal -> IO Int
+ Miso.DSL: setField :: (ToObject o, ToJSVal v) => o -> MisoString -> v -> IO ()
+ Miso.DSL: setProp :: ToJSVal val => MisoString -> val -> Object -> IO ()
+ Miso.DSL: syncCallback :: IO () -> IO JSVal
+ Miso.DSL: syncCallback' :: IO JSVal -> IO JSVal
+ Miso.DSL: syncCallback1 :: (JSVal -> IO ()) -> IO JSVal
+ Miso.DSL: syncCallback1' :: (JSVal -> IO JSVal) -> IO JSVal
+ Miso.DSL: syncCallback2 :: (JSVal -> JSVal -> IO ()) -> IO JSVal
+ Miso.DSL: syncCallback2' :: (JSVal -> JSVal -> IO JSVal) -> IO JSVal
+ Miso.DSL: syncCallback3 :: (JSVal -> JSVal -> JSVal -> IO ()) -> IO JSVal
+ Miso.DSL: syncCallback3' :: (JSVal -> JSVal -> JSVal -> IO JSVal) -> IO JSVal
+ Miso.DSL: toArgs :: ToArgs args => args -> IO [JSVal]
+ Miso.DSL: toJSVal :: ToJSVal a => a -> IO JSVal
+ Miso.DSL: toObject :: ToObject a => a -> IO Object
+ Miso.Data.Array: (!?) :: FromJSVal value => Int -> Array value -> IO value
+ Miso.Data.Array: data Array value
+ Miso.Data.Array: fromList :: ToJSVal value => [value] -> IO (Array value)
+ Miso.Data.Array: insert :: ToJSVal value => Int -> value -> Array value -> IO ()
+ Miso.Data.Array: instance Miso.DSL.FromJSVal (Miso.Data.Array.Array value)
+ Miso.Data.Array: instance Miso.DSL.ToJSVal (Miso.Data.Array.Array value)
+ Miso.Data.Array: instance Miso.DSL.ToObject (Miso.Data.Array.Array value)
+ Miso.Data.Array: lookup :: FromJSVal value => Int -> Array value -> IO (Maybe value)
+ Miso.Data.Array: member :: ToJSVal value => value -> Array value -> IO Bool
+ Miso.Data.Array: new :: IO (Array value)
+ Miso.Data.Array: null :: Array value -> IO Bool
+ Miso.Data.Array: pop :: FromJSVal a => Array a -> IO (Maybe a)
+ Miso.Data.Array: push :: ToJSVal value => value -> Array value -> IO ()
+ Miso.Data.Array: reverse :: Array a -> IO ()
+ Miso.Data.Array: shift :: FromJSVal a => Array a -> IO (Maybe a)
+ Miso.Data.Array: singleton :: ToJSVal a => a -> IO (Array a)
+ Miso.Data.Array: size :: Array value -> IO Int
+ Miso.Data.Array: splice :: ToJSVal value => Int -> Int -> [value] -> Array value -> IO (Array value)
+ Miso.Data.Array: toList :: FromJSVal value => Array value -> IO [value]
+ Miso.Data.Array: unshift :: ToJSVal a => a -> Array a -> IO Int
+ Miso.Data.Map: clear :: Map key value -> IO ()
+ Miso.Data.Map: data Map key value
+ Miso.Data.Map: delete :: ToJSVal key => key -> Map key value -> IO Bool
+ Miso.Data.Map: fromList :: (ToJSVal key, ToJSVal value) => [(key, value)] -> IO (Map key value)
+ Miso.Data.Map: has :: ToJSVal key => key -> Map key value -> IO Bool
+ Miso.Data.Map: insert :: (ToJSVal key, ToJSVal value) => key -> value -> Map key value -> IO ()
+ Miso.Data.Map: instance Miso.DSL.FromJSVal (Miso.Data.Map.Map key value)
+ Miso.Data.Map: instance Miso.DSL.ToJSVal (Miso.Data.Map.Map key value)
+ Miso.Data.Map: lookup :: (ToJSVal key, FromJSVal value) => key -> Map key value -> IO (Maybe value)
+ Miso.Data.Map: new :: IO (Map key value)
+ Miso.Data.Map: size :: Map key value -> IO Int
+ Miso.Data.Set: clear :: Set key -> IO ()
+ Miso.Data.Set: data Set key
+ Miso.Data.Set: delete :: ToJSVal key => key -> Set key -> IO Bool
+ Miso.Data.Set: difference :: ToJSVal key => Set key -> Set key -> IO (Set key)
+ Miso.Data.Set: fromList :: ToJSVal key => [key] -> IO (Set key)
+ Miso.Data.Set: insert :: ToJSVal key => key -> Set key -> IO ()
+ Miso.Data.Set: instance Miso.DSL.FromJSVal (Miso.Data.Set.Set key)
+ Miso.Data.Set: instance Miso.DSL.ToJSVal (Miso.Data.Set.Set key)
+ Miso.Data.Set: intersection :: ToJSVal key => Set key -> Set key -> IO (Set key)
+ Miso.Data.Set: isDisjoint :: ToJSVal key => Set key -> Set key -> IO Bool
+ Miso.Data.Set: isSubset :: ToJSVal key => Set key -> Set key -> IO Bool
+ Miso.Data.Set: isSuperset :: ToJSVal key => Set key -> Set key -> IO Bool
+ Miso.Data.Set: member :: ToJSVal key => key -> Set key -> IO Bool
+ Miso.Data.Set: new :: IO (Set key)
+ Miso.Data.Set: size :: Set key -> IO Int
+ Miso.Data.Set: union :: ToJSVal key => Set key -> Set key -> IO (Set key)
+ Miso.Date: data Date
+ Miso.Date: getDate :: Date -> IO Int
+ Miso.Date: getDay :: Date -> IO Int
+ Miso.Date: getFullYear :: Date -> IO Int
+ Miso.Date: getHours :: Date -> IO Int
+ Miso.Date: getMilliseconds :: Date -> IO Int
+ Miso.Date: getMinutes :: Date -> IO Int
+ Miso.Date: getMonth :: Date -> IO Int
+ Miso.Date: getSeconds :: Date -> IO Int
+ Miso.Date: getTime :: Date -> IO Double
+ Miso.Date: getTimezoneOffset :: Date -> IO Int
+ Miso.Date: getUTCDate :: Date -> IO Int
+ Miso.Date: getUTCDay :: Date -> IO Int
+ Miso.Date: getUTCFullYear :: Date -> IO Int
+ Miso.Date: getUTCHours :: Date -> IO Int
+ Miso.Date: getUTCMilliseconds :: Date -> IO Int
+ Miso.Date: getUTCMinutes :: Date -> IO Int
+ Miso.Date: getUTCMonth :: Date -> IO Int
+ Miso.Date: getUTCSeconds :: Date -> IO Int
+ Miso.Date: instance GHC.Classes.Eq Miso.Date.Date
+ Miso.Date: instance Miso.DSL.FromJSVal Miso.Date.Date
+ Miso.Date: instance Miso.DSL.ToJSVal Miso.Date.Date
+ Miso.Date: instance Miso.DSL.ToObject Miso.Date.Date
+ Miso.Date: new :: IO Date
+ Miso.Date: setDate :: Int -> Date -> IO Double
+ Miso.Date: setFullYear :: Int -> Maybe Int -> Maybe Int -> Date -> IO Double
+ Miso.Date: setHours :: Int -> Maybe Int -> Maybe Int -> Maybe Int -> Date -> IO Double
+ Miso.Date: setMilliseconds :: Int -> Date -> IO Double
+ Miso.Date: setMinutes :: Int -> Maybe Int -> Maybe Int -> Date -> IO Double
+ Miso.Date: setMonth :: Int -> Maybe Int -> Date -> IO Double
+ Miso.Date: setSeconds :: Int -> Maybe Int -> Date -> IO Double
+ Miso.Date: setTime :: Double -> Date -> IO Double
+ Miso.Date: setUTCDate :: Int -> Date -> IO Double
+ Miso.Date: setUTCFullYear :: Int -> Maybe Int -> Maybe Int -> Date -> IO Double
+ Miso.Date: setUTCHours :: Int -> Maybe Int -> Maybe Int -> Maybe Int -> Date -> IO Double
+ Miso.Date: setUTCMilliseconds :: Int -> Date -> IO Double
+ Miso.Date: setUTCMinutes :: Int -> Maybe Int -> Maybe Int -> Date -> IO Double
+ Miso.Date: setUTCMonth :: Int -> Maybe Int -> Date -> IO Double
+ Miso.Date: setUTCSeconds :: Int -> Maybe Int -> Date -> IO Double
+ Miso.Date: toDateString :: Date -> IO MisoString
+ Miso.Date: toISOString :: Date -> IO MisoString
+ Miso.Date: toJSON :: Date -> IO MisoString
+ Miso.Date: toLocaleDateString :: Date -> IO MisoString
+ Miso.Date: toLocaleString :: Date -> IO MisoString
+ Miso.Date: toLocaleTimeString :: Date -> IO MisoString
+ Miso.Date: toString :: Date -> IO MisoString
+ Miso.Date: toTimeString :: Date -> IO MisoString
+ Miso.Date: toUTCString :: Date -> IO MisoString
+ Miso.Date: valueOf :: Date -> IO Double
+ Miso.Effect: Async :: Synchronicity
+ Miso.Effect: ComponentInfo :: ComponentId -> ComponentId -> DOMRef -> ComponentInfo parent
+ Miso.Effect: Schedule :: Synchronicity -> (Sink action -> IO ()) -> Schedule action
+ Miso.Effect: Sync :: Synchronicity
+ Miso.Effect: [_componentInfoDOMRef] :: ComponentInfo parent -> DOMRef
+ Miso.Effect: [_componentInfoId] :: ComponentInfo parent -> ComponentId
+ Miso.Effect: [_componentInfoParentId] :: ComponentInfo parent -> ComponentId
+ Miso.Effect: afterAll :: IO () -> Effect parent model action -> Effect parent model action
+ Miso.Effect: batch :: [IO action] -> Effect parent model action
+ Miso.Effect: batch_ :: [IO ()] -> Effect parent model action
+ Miso.Effect: beforeAll :: IO () -> Effect parent model action -> Effect parent model action
+ Miso.Effect: componentInfoDOMRef :: Lens (ComponentInfo parent) DOMRef
+ Miso.Effect: componentInfoId :: Lens (ComponentInfo parent) ComponentId
+ Miso.Effect: componentInfoParentId :: Lens (ComponentInfo parent) ComponentId
+ Miso.Effect: data ComponentInfo parent
+ Miso.Effect: data Schedule action
+ Miso.Effect: data Synchronicity
+ Miso.Effect: for :: Foldable f => IO (f action) -> Effect parent model action
+ Miso.Effect: infixl 0 <#
+ Miso.Effect: infixr 0 #>
+ Miso.Effect: instance GHC.Classes.Eq Miso.Effect.Synchronicity
+ Miso.Effect: instance GHC.Show.Show Miso.Effect.Synchronicity
+ Miso.Effect: io :: IO action -> Effect parent model action
+ Miso.Effect: io_ :: IO () -> Effect parent model action
+ Miso.Effect: issue :: action -> Effect parent model action
+ Miso.Effect: mkComponentInfo :: ComponentId -> ComponentId -> DOMRef -> ComponentInfo parent
+ Miso.Effect: modifyAllIO :: (IO () -> IO ()) -> Effect parent model action -> Effect parent model action
+ Miso.Effect: noop :: action -> Effect parent model action
+ Miso.Effect: runEffect :: Effect parent model action -> ComponentInfo parent -> model -> (model, [Schedule action])
+ Miso.Effect: sync :: IO action -> Effect parent model action
+ Miso.Effect: sync_ :: IO () -> Effect parent model action
+ Miso.Effect: type ComponentId = Int
+ Miso.Effect: type DOMRef = JSVal
+ Miso.Effect: type Effect parent model action = RWS ComponentInfo parent [Schedule action] model ()
+ Miso.Effect: withSink :: (Sink action -> IO ()) -> Effect parent model action
+ Miso.Event: BUBBLE :: Phase
+ Miso.Event: CAPTURE :: Phase
+ Miso.Event: data Phase
+ Miso.Event: on :: MisoString -> Decoder r -> (r -> DOMRef -> action) -> Attribute action
+ Miso.Event: onBeforeCreated :: action -> Attribute action
+ Miso.Event: onBeforeDestroyed :: action -> Attribute action
+ Miso.Event: onBeforeDestroyedWith :: (DOMRef -> action) -> Attribute action
+ Miso.Event: onCapture :: MisoString -> Decoder r -> (r -> DOMRef -> action) -> Attribute action
+ Miso.Event: onCreated :: action -> Attribute action
+ Miso.Event: onCreatedWith :: (DOMRef -> action) -> Attribute action
+ Miso.Event: onDestroyed :: action -> Attribute action
+ Miso.Event: onWithOptions :: Phase -> Options -> MisoString -> Decoder r -> (r -> DOMRef -> action) -> Attribute action
+ Miso.Event.Decoder: instance Miso.DSL.ToJSVal Miso.Event.Decoder.DecodeTarget
+ Miso.Event.Decoder: pointerDecoder :: Decoder PointerEvent
+ Miso.Event.Types: BUBBLE :: Phase
+ Miso.Event.Types: CAPTURE :: Phase
+ Miso.Event.Types: MousePointerType :: PointerType
+ Miso.Event.Types: PenPointerType :: PointerType
+ Miso.Event.Types: PointerEvent :: PointerType -> Int -> Bool -> (Double, Double) -> (Double, Double) -> (Double, Double) -> (Double, Double) -> (Double, Double) -> Double -> Int -> PointerEvent
+ Miso.Event.Types: TouchPointerType :: PointerType
+ Miso.Event.Types: UnknownPointerType :: MisoString -> PointerType
+ Miso.Event.Types: [_preventDefault] :: Options -> Bool
+ Miso.Event.Types: [_stopPropagation] :: Options -> Bool
+ Miso.Event.Types: [altKey] :: KeyInfo -> !Bool
+ Miso.Event.Types: [button] :: PointerEvent -> Int
+ Miso.Event.Types: [client] :: PointerEvent -> (Double, Double)
+ Miso.Event.Types: [ctrlKey] :: KeyInfo -> !Bool
+ Miso.Event.Types: [isPrimary] :: PointerEvent -> Bool
+ Miso.Event.Types: [metaKey] :: KeyInfo -> !Bool
+ Miso.Event.Types: [offset] :: PointerEvent -> (Double, Double)
+ Miso.Event.Types: [page] :: PointerEvent -> (Double, Double)
+ Miso.Event.Types: [pointerId] :: PointerEvent -> Int
+ Miso.Event.Types: [pointerType] :: PointerEvent -> PointerType
+ Miso.Event.Types: [pressure] :: PointerEvent -> Double
+ Miso.Event.Types: [screen] :: PointerEvent -> (Double, Double)
+ Miso.Event.Types: [shiftKey] :: KeyInfo -> !Bool
+ Miso.Event.Types: [tilt] :: PointerEvent -> (Double, Double)
+ Miso.Event.Types: clipboardEvents :: Events
+ Miso.Event.Types: data Phase
+ Miso.Event.Types: data PointerEvent
+ Miso.Event.Types: data PointerType
+ Miso.Event.Types: dragEvents :: Events
+ Miso.Event.Types: instance GHC.Base.Monoid Miso.Event.Types.Options
+ Miso.Event.Types: instance GHC.Base.Semigroup Miso.Event.Types.Options
+ Miso.Event.Types: instance GHC.Classes.Eq Miso.Event.Types.Phase
+ Miso.Event.Types: instance GHC.Classes.Eq Miso.Event.Types.PointerEvent
+ Miso.Event.Types: instance GHC.Classes.Eq Miso.Event.Types.PointerType
+ Miso.Event.Types: instance GHC.Num.Num Miso.Event.Types.KeyCode
+ Miso.Event.Types: instance GHC.Show.Show Miso.Event.Types.Phase
+ Miso.Event.Types: instance GHC.Show.Show Miso.Event.Types.PointerEvent
+ Miso.Event.Types: instance GHC.Show.Show Miso.Event.Types.PointerType
+ Miso.Event.Types: instance Miso.DSL.ToJSVal Miso.Event.Types.Options
+ Miso.Event.Types: instance Miso.DSL.ToJSVal Miso.Event.Types.Phase
+ Miso.Event.Types: instance Miso.JSON.FromJSON Miso.Event.Types.Checked
+ Miso.Event.Types: instance Miso.JSON.FromJSON Miso.Event.Types.KeyCode
+ Miso.Event.Types: instance Miso.JSON.FromJSON Miso.Event.Types.PointerType
+ Miso.Event.Types: keyboardEvents :: Events
+ Miso.Event.Types: mediaEvents :: Events
+ Miso.Event.Types: mouseEvents :: Events
+ Miso.Event.Types: pointerEvents :: Events
+ Miso.Event.Types: preventDefault :: Options
+ Miso.Event.Types: stopPropagation :: Options
+ Miso.Event.Types: touchEvents :: Events
+ Miso.Event.Types: type Events = Map MisoString Phase
+ Miso.EventSource: BLOB :: Blob -> Payload value
+ Miso.EventSource: BUFFER :: ArrayBuffer -> Payload value
+ Miso.EventSource: EventSource :: Int -> EventSource
+ Miso.EventSource: JSON :: value -> Payload value
+ Miso.EventSource: TEXT :: MisoString -> Payload value
+ Miso.EventSource: close :: EventSource -> Effect parent model action
+ Miso.EventSource: connectJSON :: FromJSON value => URL -> (EventSource -> action) -> (value -> action) -> (MisoString -> action) -> Effect parent model action
+ Miso.EventSource: connectText :: URL -> (EventSource -> action) -> (MisoString -> action) -> (MisoString -> action) -> Effect parent model action
+ Miso.EventSource: data Payload value
+ Miso.EventSource: emptyEventSource :: EventSource
+ Miso.EventSource: newtype EventSource
+ Miso.EventSource: socketState :: WebSocket -> (SocketState -> action) -> Effect parent model action
+ Miso.EventSource: type URL = MisoString
+ Miso.FFI: ArrayBuffer :: JSVal -> ArrayBuffer
+ Miso.FFI: Blob :: JSVal -> Blob
+ Miso.FFI: Date :: JSVal -> Date
+ Miso.FFI: Event :: JSVal -> Event
+ Miso.FFI: File :: JSVal -> File
+ Miso.FFI: FileReader :: JSVal -> FileReader
+ Miso.FFI: FormData :: JSVal -> FormData
+ Miso.FFI: Image :: JSVal -> Image
+ Miso.FFI: Response :: Maybe Int -> Map MisoString MisoString -> Maybe MisoString -> body -> Response body
+ Miso.FFI: URLSearchParams :: JSVal -> URLSearchParams
+ Miso.FFI: Uint8Array :: JSVal -> Uint8Array
+ Miso.FFI: [body] :: Response body -> body
+ Miso.FFI: [errorMessage] :: Response body -> Maybe MisoString
+ Miso.FFI: [headers] :: Response body -> Map MisoString MisoString
+ Miso.FFI: [status] :: Response body -> Maybe Int
+ Miso.FFI: addScript :: Bool -> MisoString -> IO JSVal
+ Miso.FFI: addScriptImportMap :: MisoString -> IO JSVal
+ Miso.FFI: addSrc :: MisoString -> Bool -> IO JSVal
+ Miso.FFI: addStyle :: MisoString -> IO JSVal
+ Miso.FFI: addStyleSheet :: MisoString -> Bool -> IO JSVal
+ Miso.FFI: asyncCallback2 :: (JSVal -> JSVal -> IO ()) -> IO JSVal
+ Miso.FFI: callFunction :: ToArgs args => JSVal -> MisoString -> args -> IO JSVal
+ Miso.FFI: castJSVal :: FromJSVal a => JSVal -> IO (Maybe a)
+ Miso.FFI: click :: () -> JSVal -> IO ()
+ Miso.FFI: consoleError :: MisoString -> IO ()
+ Miso.FFI: consoleLog' :: ToArgs a => a -> IO ()
+ Miso.FFI: consoleWarn :: MisoString -> IO ()
+ Miso.FFI: data Response body
+ Miso.FFI: dispatchEvent :: Event -> IO ()
+ Miso.FFI: fetch :: (FromJSVal success, FromJSVal error) => MisoString -> MisoString -> Maybe JSVal -> [(MisoString, MisoString)] -> (Response success -> IO ()) -> (Response error -> IO ()) -> CONTENT_TYPE -> IO ()
+ Miso.FFI: files :: JSVal -> IO [JSVal]
+ Miso.FFI: flush :: IO ()
+ Miso.FFI: getMilliseconds :: Date -> IO Double
+ Miso.FFI: getProperty :: JSVal -> MisoString -> IO JSVal
+ Miso.FFI: getSeconds :: Date -> IO Double
+ Miso.FFI: inline :: (FromJSVal return, ToObject object) => MisoString -> object -> IO return
+ Miso.FFI: isOnLine :: IO Bool
+ Miso.FFI: locationReload :: IO ()
+ Miso.FFI: mathRandom :: IO Double
+ Miso.FFI: modelHydration :: Int -> Object -> IO ()
+ Miso.FFI: mountComponent :: Int -> Object -> IO ()
+ Miso.FFI: newCustomEvent :: ToArgs args => args -> IO Event
+ Miso.FFI: newDate :: IO Date
+ Miso.FFI: newEvent :: ToArgs args => args -> IO Event
+ Miso.FFI: newFileReader :: IO FileReader
+ Miso.FFI: newImage :: MisoString -> IO Image
+ Miso.FFI: newtype ArrayBuffer
+ Miso.FFI: newtype Blob
+ Miso.FFI: newtype Date
+ Miso.FFI: newtype Event
+ Miso.FFI: newtype File
+ Miso.FFI: newtype FileReader
+ Miso.FFI: newtype FormData
+ Miso.FFI: newtype Image
+ Miso.FFI: newtype URLSearchParams
+ Miso.FFI: newtype Uint8Array
+ Miso.FFI: nextSibling :: JSVal -> IO JSVal
+ Miso.FFI: previousSibling :: JSVal -> IO JSVal
+ Miso.FFI: removeChild :: JSVal -> JSVal -> IO ()
+ Miso.FFI: removeEventListener :: JSVal -> MisoString -> Function -> IO ()
+ Miso.FFI: select :: MisoString -> IO ()
+ Miso.FFI: setDrawingContext :: MisoString -> IO ()
+ Miso.FFI: setSelectionRange :: MisoString -> Int -> Int -> IO ()
+ Miso.FFI: setValue :: JSVal -> MisoString -> IO ()
+ Miso.FFI: splitmix32 :: Double -> IO JSVal
+ Miso.FFI: syncCallback :: IO () -> IO JSVal
+ Miso.FFI: syncCallback1 :: (JSVal -> IO ()) -> IO JSVal
+ Miso.FFI: toLocaleString :: Date -> IO MisoString
+ Miso.FFI: unmountComponent :: Int -> IO ()
+ Miso.Fetch: ARRAY_BUFFER :: CONTENT_TYPE
+ Miso.Fetch: BLOB :: CONTENT_TYPE
+ Miso.Fetch: BYTES :: CONTENT_TYPE
+ Miso.Fetch: FORM_DATA :: CONTENT_TYPE
+ Miso.Fetch: JSON :: CONTENT_TYPE
+ Miso.Fetch: NONE :: CONTENT_TYPE
+ Miso.Fetch: Response :: Maybe Int -> Map MisoString MisoString -> Maybe MisoString -> body -> Response body
+ Miso.Fetch: TEXT :: CONTENT_TYPE
+ Miso.Fetch: [body] :: Response body -> body
+ Miso.Fetch: [errorMessage] :: Response body -> Maybe MisoString
+ Miso.Fetch: [headers] :: Response body -> Map MisoString MisoString
+ Miso.Fetch: [status] :: Response body -> Maybe Int
+ Miso.Fetch: accept :: MisoString
+ Miso.Fetch: applicationJSON :: MisoString
+ Miso.Fetch: contentType :: MisoString
+ Miso.Fetch: data CONTENT_TYPE
+ Miso.Fetch: data Response body
+ Miso.Fetch: fetch :: (FromJSVal success, FromJSVal error) => MisoString -> MisoString -> Maybe JSVal -> [(MisoString, MisoString)] -> (Response success -> IO ()) -> (Response error -> IO ()) -> CONTENT_TYPE -> IO ()
+ Miso.Fetch: formData :: MisoString
+ Miso.Fetch: getArrayBuffer :: FromJSVal error => MisoString -> [(MisoString, MisoString)] -> (Response ArrayBuffer -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: getBlob :: FromJSVal error => MisoString -> [(MisoString, MisoString)] -> (Response Blob -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: getFormData :: FromJSVal error => MisoString -> [(MisoString, MisoString)] -> (Response FormData -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: getJSON :: (FromJSON body, FromJSVal error) => MisoString -> [(MisoString, MisoString)] -> (Response body -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: getText :: FromJSVal error => MisoString -> [(MisoString, MisoString)] -> (Response MisoString -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: getUint8Array :: FromJSVal error => MisoString -> [(MisoString, MisoString)] -> (Response Uint8Array -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: postArrayBuffer :: FromJSVal error => MisoString -> ArrayBuffer -> [(MisoString, MisoString)] -> (Response () -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: postBlob :: FromJSVal error => MisoString -> Blob -> [(MisoString, MisoString)] -> (Response () -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: postFormData :: FromJSVal error => MisoString -> FormData -> [(MisoString, MisoString)] -> (Response () -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: postImage :: FromJSVal error => MisoString -> Image -> [(MisoString, MisoString)] -> (Response () -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: postJSON :: (FromJSVal error, ToJSON body) => MisoString -> body -> [(MisoString, MisoString)] -> (Response () -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: postJSON' :: (FromJSVal error, ToJSON body, FromJSON return) => MisoString -> body -> [(MisoString, MisoString)] -> (Response return -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: postText :: FromJSVal error => MisoString -> MisoString -> [(MisoString, MisoString)] -> (Response () -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: postUint8Array :: FromJSVal error => MisoString -> Uint8Array -> [(MisoString, MisoString)] -> (Response () -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: putArrayBuffer :: FromJSVal error => MisoString -> ArrayBuffer -> [(MisoString, MisoString)] -> (Response () -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: putBlob :: FromJSVal error => MisoString -> Blob -> [(MisoString, MisoString)] -> (Response () -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: putFormData :: FromJSVal error => MisoString -> FormData -> [(MisoString, MisoString)] -> (Response () -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: putImage :: FromJSVal error => MisoString -> Image -> [(MisoString, MisoString)] -> (Response () -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: putJSON :: (FromJSVal error, ToJSON body) => MisoString -> body -> [(MisoString, MisoString)] -> (Response () -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: putText :: FromJSVal error => MisoString -> MisoString -> [(MisoString, MisoString)] -> (Response () -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: putUint8Array :: FromJSVal error => MisoString -> Uint8Array -> [(MisoString, MisoString)] -> (Response () -> action) -> (Response error -> action) -> Effect parent model action
+ Miso.Fetch: textPlain :: MisoString
+ Miso.Fetch: type Body = JSVal
+ Miso.Html.Element: area_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: base_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: data_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: dialog_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: doctype_ :: View model action
+ Miso.Html.Element: fencedframe_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: head_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: hgroup_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: html_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: map_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: meta_ :: [Attribute action] -> View model action
+ Miso.Html.Element: noscript_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: picture_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: search_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: slot_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: svg_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: template_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Element: title_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Html.Event: onAbort :: action -> Attribute action
+ Miso.Html.Event: onAbortWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onCanPlay :: action -> Attribute action
+ Miso.Html.Event: onCanPlayThrough :: action -> Attribute action
+ Miso.Html.Event: onCanPlayThroughWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onCanPlayWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onChangeWith :: (MisoString -> DOMRef -> action) -> Attribute action
+ Miso.Html.Event: onClickCapture :: action -> Attribute action
+ Miso.Html.Event: onClickPrevent :: action -> Attribute action
+ Miso.Html.Event: onClickWith :: (DOMRef -> action) -> Attribute action
+ Miso.Html.Event: onClickWithOptions :: Options -> action -> Attribute action
+ Miso.Html.Event: onContextMenuWithOptions :: Options -> action -> Attribute action
+ Miso.Html.Event: onDoubleClickWith :: (DOMRef -> action) -> Attribute action
+ Miso.Html.Event: onDoubleClickWithOptions :: Options -> action -> Attribute action
+ Miso.Html.Event: onDragEndWithOptions :: Options -> action -> Attribute action
+ Miso.Html.Event: onDragEnterWithOptions :: Options -> action -> Attribute action
+ Miso.Html.Event: onDragLeaveWithOptions :: Options -> action -> Attribute action
+ Miso.Html.Event: onDragOverWithOptions :: Options -> action -> Attribute action
+ Miso.Html.Event: onDragStartWithOptions :: Options -> action -> Attribute action
+ Miso.Html.Event: onDragWithOptions :: Options -> action -> Attribute action
+ Miso.Html.Event: onDropWithOptions :: Options -> action -> Attribute action
+ Miso.Html.Event: onDurationChange :: action -> Attribute action
+ Miso.Html.Event: onDurationChangeWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onEmptied :: action -> Attribute action
+ Miso.Html.Event: onEmptiedWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onEnded :: action -> Attribute action
+ Miso.Html.Event: onEndedWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onEnter :: action -> action -> Attribute action
+ Miso.Html.Event: onError :: action -> Attribute action
+ Miso.Html.Event: onErrorWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onLoad :: action -> Attribute action
+ Miso.Html.Event: onLoadStart :: action -> Attribute action
+ Miso.Html.Event: onLoadStartWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onLoadedData :: action -> Attribute action
+ Miso.Html.Event: onLoadedDataWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onLoadedMetadata :: action -> Attribute action
+ Miso.Html.Event: onLoadedMetadataWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onPause :: action -> Attribute action
+ Miso.Html.Event: onPauseWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onPlay :: action -> Attribute action
+ Miso.Html.Event: onPlayWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onPlaying :: action -> Attribute action
+ Miso.Html.Event: onPlayingWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onPointerCancel :: (PointerEvent -> action) -> Attribute action
+ Miso.Html.Event: onPointerDown :: (PointerEvent -> action) -> Attribute action
+ Miso.Html.Event: onPointerEnter :: (PointerEvent -> action) -> Attribute action
+ Miso.Html.Event: onPointerLeave :: (PointerEvent -> action) -> Attribute action
+ Miso.Html.Event: onPointerMove :: (PointerEvent -> action) -> Attribute action
+ Miso.Html.Event: onPointerOut :: (PointerEvent -> action) -> Attribute action
+ Miso.Html.Event: onPointerOver :: (PointerEvent -> action) -> Attribute action
+ Miso.Html.Event: onPointerUp :: (PointerEvent -> action) -> Attribute action
+ Miso.Html.Event: onProgress :: action -> Attribute action
+ Miso.Html.Event: onProgressWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onRateChange :: action -> Attribute action
+ Miso.Html.Event: onRateChangeWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onSeeked :: action -> Attribute action
+ Miso.Html.Event: onSeekedWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onSeeking :: action -> Attribute action
+ Miso.Html.Event: onSeekingWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onSelect :: (MisoString -> action) -> Attribute action
+ Miso.Html.Event: onStalled :: action -> Attribute action
+ Miso.Html.Event: onStalledWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onSuspend :: action -> Attribute action
+ Miso.Html.Event: onSuspendWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onTimeUpdate :: action -> Attribute action
+ Miso.Html.Event: onTimeUpdateWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onTouchCancel :: action -> Attribute action
+ Miso.Html.Event: onTouchCancelWithOptions :: Options -> action -> Attribute action
+ Miso.Html.Event: onTouchEnd :: action -> Attribute action
+ Miso.Html.Event: onTouchEndWithOptions :: Options -> action -> Attribute action
+ Miso.Html.Event: onTouchMove :: action -> Attribute action
+ Miso.Html.Event: onTouchMoveWithOptions :: Options -> action -> Attribute action
+ Miso.Html.Event: onTouchStart :: action -> Attribute action
+ Miso.Html.Event: onTouchStartWithOptions :: Options -> action -> Attribute action
+ Miso.Html.Event: onUnload :: action -> Attribute action
+ Miso.Html.Event: onVolumeChange :: action -> Attribute action
+ Miso.Html.Event: onVolumeChangeWith :: (Media -> action) -> Attribute action
+ Miso.Html.Event: onWaiting :: action -> Attribute action
+ Miso.Html.Event: onWaitingWith :: (Media -> action) -> Attribute action
+ Miso.Html.Property: aria_ :: MisoString -> MisoString -> Attribute action
+ Miso.Html.Property: autocorrect_ :: Bool -> Attribute action
+ Miso.Html.Property: className :: MisoString -> Attribute action
+ Miso.Html.Property: classes_ :: [MisoString] -> Attribute action
+ Miso.Html.Property: currentTime_ :: Double -> Attribute action
+ Miso.Html.Property: defaultMuted_ :: Bool -> Attribute action
+ Miso.Html.Property: defaultPlaybackRate_ :: Double -> Attribute action
+ Miso.Html.Property: draggable_ :: Bool -> Attribute action
+ Miso.Html.Property: frameborder_ :: MisoString -> Attribute action
+ Miso.Html.Property: inert_ :: Bool -> Attribute action
+ Miso.Html.Property: label_ :: MisoString -> Attribute action
+ Miso.Html.Property: lang_ :: MisoString -> Attribute action
+ Miso.Html.Property: mediaGroup_ :: MisoString -> Attribute action
+ Miso.Html.Property: muted_ :: Bool -> Attribute action
+ Miso.Html.Property: noValidate_ :: Bool -> Attribute action
+ Miso.Html.Property: open_ :: Bool -> Attribute action
+ Miso.Html.Property: playbackRate_ :: Double -> Attribute action
+ Miso.Html.Property: role_ :: MisoString -> Attribute action
+ Miso.Html.Property: scrolling_ :: MisoString -> Attribute action
+ Miso.Html.Property: seeking_ :: Bool -> Attribute action
+ Miso.Html.Property: spellcheck_ :: Bool -> Attribute action
+ Miso.Html.Property: tabindex_ :: MisoString -> Attribute action
+ Miso.Html.Property: volume_ :: Double -> Attribute action
+ Miso.Html.Property: xmlns_ :: MisoString -> Attribute action
+ Miso.Html.Render: class ToHtml a
+ Miso.Html.Render: instance Miso.Html.Render.ToHtml (Miso.Types.View m a)
+ Miso.Html.Render: instance Miso.Html.Render.ToHtml [Miso.Types.View m a]
+ Miso.Html.Render: toHtml :: ToHtml a => a -> ByteString
+ Miso.JSON: ($dmparseJSON) :: (FromJSON a, Generic a, GFromJSON (Rep a)) => Value -> Parser a
+ Miso.JSON: ($dmtoJSON) :: (ToJSON a, Generic a, GToJSON (Rep a)) => a -> Value
+ Miso.JSON: (.!=) :: Parser (Maybe a) -> a -> Parser a
+ Miso.JSON: (.:!) :: FromJSON a => Object -> MisoString -> Parser (Maybe a)
+ Miso.JSON: (.:) :: FromJSON a => Object -> MisoString -> Parser a
+ Miso.JSON: (.:?) :: FromJSON a => Object -> MisoString -> Parser (Maybe a)
+ Miso.JSON: (.=) :: ToJSON v => MisoString -> v -> Pair
+ Miso.JSON: Array :: [Value] -> Value
+ Miso.JSON: Bool :: Bool -> Value
+ Miso.JSON: Config :: Int -> Config
+ Miso.JSON: Error :: MisoString -> Result a
+ Miso.JSON: Null :: Value
+ Miso.JSON: Number :: Double -> Value
+ Miso.JSON: Object :: Map MisoString Value -> Value
+ Miso.JSON: Options :: (String -> String) -> Options
+ Miso.JSON: Parser :: Either MisoString a -> Parser a
+ Miso.JSON: String :: MisoString -> Value
+ Miso.JSON: Success :: a -> Result a
+ Miso.JSON: [fieldLabelModifier] :: Options -> String -> String
+ Miso.JSON: [spaces] :: Config -> Int
+ Miso.JSON: [unParser] :: Parser a -> Either MisoString a
+ Miso.JSON: camelTo2 :: Char -> String -> String
+ Miso.JSON: class FromJSON a
+ Miso.JSON: class GFromJSON (f :: Type -> Type)
+ Miso.JSON: class GToJSON (f :: Type -> Type)
+ Miso.JSON: class ToJSON a
+ Miso.JSON: data Options
+ Miso.JSON: data Result a
+ Miso.JSON: data Value
+ Miso.JSON: decode :: FromJSON a => MisoString -> Maybe a
+ Miso.JSON: decodePure :: MisoString -> Either String Value
+ Miso.JSON: defConfig :: Config
+ Miso.JSON: defaultOptions :: Options
+ Miso.JSON: eitherDecode :: FromJSON a => MisoString -> Either MisoString a
+ Miso.JSON: emptyArray :: Value
+ Miso.JSON: emptyObject :: Value
+ Miso.JSON: encode :: ToJSON a => a -> MisoString
+ Miso.JSON: encodePretty :: ToJSON a => a -> MisoString
+ Miso.JSON: encodePretty' :: ToJSON a => Config -> a -> MisoString
+ Miso.JSON: encodePure :: ToJSON a => a -> MisoString
+ Miso.JSON: fromJSON :: FromJSON a => Value -> Result a
+ Miso.JSON: fromJSVal_Value :: JSVal -> IO (Maybe Value)
+ Miso.JSON: gParseJSON :: GFromJSON f => Options -> Value -> Parser (f a)
+ Miso.JSON: gToJSON :: GToJSON f => Options -> [Pair] -> f a -> [Pair]
+ Miso.JSON: genericParseJSON :: (Generic a, GFromJSON (Rep a)) => Options -> Value -> Parser a
+ Miso.JSON: genericToJSON :: (Generic a, GToJSON (Rep a)) => Options -> a -> Value
+ Miso.JSON: infixr 8 .=
+ Miso.JSON: instance ((TypeError ...), Miso.JSON.GFromJSON a, Miso.JSON.GFromJSON b) => Miso.JSON.GFromJSON (a GHC.Generics.:+: b)
+ Miso.JSON: instance ((TypeError ...), Miso.JSON.GToJSON a, Miso.JSON.GToJSON b) => Miso.JSON.GToJSON (a GHC.Generics.:+: b)
+ Miso.JSON: instance (GHC.Generics.Selector s, Miso.JSON.FromJSON a) => Miso.JSON.GFromJSON (GHC.Generics.S1 s (GHC.Generics.K1 i (GHC.Maybe.Maybe a)))
+ Miso.JSON: instance (GHC.Generics.Selector s, Miso.JSON.FromJSON a) => Miso.JSON.GFromJSON (GHC.Generics.S1 s (GHC.Generics.K1 i a))
+ Miso.JSON: instance (GHC.Generics.Selector s, Miso.JSON.ToJSON a) => Miso.JSON.GToJSON (GHC.Generics.S1 s (GHC.Generics.K1 i a))
+ Miso.JSON: instance (Miso.JSON.FromJSON a, Miso.JSON.FromJSON b) => Miso.JSON.FromJSON (a, b)
+ Miso.JSON: instance (Miso.JSON.FromJSON a, Miso.JSON.FromJSON b, Miso.JSON.FromJSON c) => Miso.JSON.FromJSON (a, b, c)
+ Miso.JSON: instance (Miso.JSON.FromJSON a, Miso.JSON.FromJSON b, Miso.JSON.FromJSON c, Miso.JSON.FromJSON d) => Miso.JSON.FromJSON (a, b, c, d)
+ Miso.JSON: instance (Miso.JSON.GFromJSON a, Miso.JSON.GFromJSON b) => Miso.JSON.GFromJSON (a GHC.Generics.:*: b)
+ Miso.JSON: instance (Miso.JSON.GToJSON a, Miso.JSON.GToJSON b) => Miso.JSON.GToJSON (a GHC.Generics.:*: b)
+ Miso.JSON: instance (Miso.JSON.ToJSON a, Miso.JSON.ToJSON b) => Miso.JSON.ToJSON (a, b)
+ Miso.JSON: instance (Miso.JSON.ToJSON a, Miso.JSON.ToJSON b, Miso.JSON.ToJSON c) => Miso.JSON.ToJSON (a, b, c)
+ Miso.JSON: instance (Miso.JSON.ToJSON a, Miso.JSON.ToJSON b, Miso.JSON.ToJSON c, Miso.JSON.ToJSON d) => Miso.JSON.ToJSON (a, b, c, d)
+ Miso.JSON: instance Control.Monad.Fail.MonadFail Miso.JSON.Parser
+ Miso.JSON: instance GHC.Base.Alternative Miso.JSON.Parser
+ Miso.JSON: instance GHC.Base.Applicative Miso.JSON.Parser
+ Miso.JSON: instance GHC.Base.Functor Miso.JSON.Parser
+ Miso.JSON: instance GHC.Base.Monad Miso.JSON.Parser
+ Miso.JSON: instance GHC.Base.MonadPlus Miso.JSON.Parser
+ Miso.JSON: instance GHC.Classes.Eq Miso.JSON.Config
+ Miso.JSON: instance GHC.Show.Show Miso.JSON.Config
+ Miso.JSON: instance Miso.JSON.FromJSON ()
+ Miso.JSON: instance Miso.JSON.FromJSON Data.Text.Internal.Lazy.Text
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Base.String
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Int.Int16
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Int.Int32
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Int.Int64
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Int.Int8
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Num.Integer.Integer
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Num.Natural.Natural
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Types.Bool
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Types.Char
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Types.Double
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Types.Float
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Types.Int
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Types.Ordering
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Types.Word
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Word.Word16
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Word.Word32
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Word.Word64
+ Miso.JSON: instance Miso.JSON.FromJSON GHC.Word.Word8
+ Miso.JSON: instance Miso.JSON.FromJSON Miso.JSON.Types.Value
+ Miso.JSON: instance Miso.JSON.FromJSON Miso.String.MisoString
+ Miso.JSON: instance Miso.JSON.FromJSON a => Miso.JSON.FromJSON (GHC.Maybe.Maybe a)
+ Miso.JSON: instance Miso.JSON.FromJSON a => Miso.JSON.FromJSON [a]
+ Miso.JSON: instance Miso.JSON.FromJSON v => Miso.JSON.FromJSON (Data.Map.Internal.Map Miso.String.MisoString v)
+ Miso.JSON: instance Miso.JSON.GFromJSON GHC.Generics.U1
+ Miso.JSON: instance Miso.JSON.GFromJSON a => Miso.JSON.GFromJSON (GHC.Generics.C1 i a)
+ Miso.JSON: instance Miso.JSON.GFromJSON a => Miso.JSON.GFromJSON (GHC.Generics.D1 i a)
+ Miso.JSON: instance Miso.JSON.GToJSON GHC.Generics.U1
+ Miso.JSON: instance Miso.JSON.GToJSON GHC.Generics.V1
+ Miso.JSON: instance Miso.JSON.GToJSON a => Miso.JSON.GToJSON (GHC.Generics.C1 i a)
+ Miso.JSON: instance Miso.JSON.GToJSON a => Miso.JSON.GToJSON (GHC.Generics.D1 i a)
+ Miso.JSON: instance Miso.JSON.ToJSON ()
+ Miso.JSON: instance Miso.JSON.ToJSON Data.Text.Internal.Lazy.Text
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Base.String
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Int.Int16
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Int.Int32
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Int.Int64
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Int.Int8
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Num.Integer.Integer
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Num.Natural.Natural
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Types.Bool
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Types.Char
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Types.Double
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Types.Float
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Types.Int
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Types.Word
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Word.Word16
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Word.Word32
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Word.Word64
+ Miso.JSON: instance Miso.JSON.ToJSON GHC.Word.Word8
+ Miso.JSON: instance Miso.JSON.ToJSON Miso.JSON.Types.Value
+ Miso.JSON: instance Miso.JSON.ToJSON Miso.String.MisoString
+ Miso.JSON: instance Miso.JSON.ToJSON a => Miso.JSON.ToJSON (GHC.Maybe.Maybe a)
+ Miso.JSON: instance Miso.JSON.ToJSON a => Miso.JSON.ToJSON [a]
+ Miso.JSON: instance Miso.JSON.ToJSON v => Miso.JSON.ToJSON (Data.Map.Internal.Map Miso.String.MisoString v)
+ Miso.JSON: instance Miso.String.FromMisoString Miso.JSON.Types.Value
+ Miso.JSON: instance Miso.String.ToMisoString Miso.JSON.Types.Value
+ Miso.JSON: jsonParse :: MisoString -> IO JSVal
+ Miso.JSON: jsonStringify :: JSVal -> IO MisoString
+ Miso.JSON: newtype Config
+ Miso.JSON: newtype Parser a
+ Miso.JSON: object :: [Pair] -> Value
+ Miso.JSON: parseEither :: (a -> Parser b) -> a -> Either MisoString b
+ Miso.JSON: parseJSON :: FromJSON a => Value -> Parser a
+ Miso.JSON: parseMaybe :: (a -> Parser b) -> a -> Maybe b
+ Miso.JSON: toJSON :: ToJSON a => a -> Value
+ Miso.JSON: toJSVal_Value :: Value -> IO JSVal
+ Miso.JSON: type Object = Map MisoString Value
+ Miso.JSON: type Pair = (MisoString, Value)
+ Miso.JSON: typeMismatch :: MisoString -> Value -> Parser a
+ Miso.JSON: withArray :: MisoString -> ([Value] -> Parser a) -> Value -> Parser a
+ Miso.JSON: withBool :: MisoString -> (Bool -> Parser a) -> Value -> Parser a
+ Miso.JSON: withNumber :: MisoString -> (Double -> Parser a) -> Value -> Parser a
+ Miso.JSON: withObject :: MisoString -> (Object -> Parser a) -> Value -> Parser a
+ Miso.JSON: withText :: MisoString -> (MisoString -> Parser a) -> Value -> Parser a
+ Miso.JSON.Lexer: TokenBool :: Bool -> Token
+ Miso.JSON.Lexer: TokenNull :: Token
+ Miso.JSON.Lexer: TokenNumber :: Double -> Token
+ Miso.JSON.Lexer: TokenPunctuator :: Char -> Token
+ Miso.JSON.Lexer: TokenString :: MisoString -> Token
+ Miso.JSON.Lexer: data Token
+ Miso.JSON.Lexer: instance GHC.Classes.Eq Miso.JSON.Lexer.Token
+ Miso.JSON.Lexer: instance GHC.Show.Show Miso.JSON.Lexer.Token
+ Miso.JSON.Lexer: tokens :: Lexer [Token]
+ Miso.JSON.Parser: decodePure :: MisoString -> Either String Value
+ Miso.JSON.Types: Array :: [Value] -> Value
+ Miso.JSON.Types: Bool :: Bool -> Value
+ Miso.JSON.Types: Error :: MisoString -> Result a
+ Miso.JSON.Types: Null :: Value
+ Miso.JSON.Types: Number :: Double -> Value
+ Miso.JSON.Types: Object :: Map MisoString Value -> Value
+ Miso.JSON.Types: String :: MisoString -> Value
+ Miso.JSON.Types: Success :: a -> Result a
+ Miso.JSON.Types: data Result a
+ Miso.JSON.Types: data Value
+ Miso.JSON.Types: instance Control.Monad.Fail.MonadFail Miso.JSON.Types.Result
+ Miso.JSON.Types: instance Data.Foldable.Foldable Miso.JSON.Types.Result
+ Miso.JSON.Types: instance Data.String.IsString Miso.JSON.Types.Value
+ Miso.JSON.Types: instance Data.Traversable.Traversable Miso.JSON.Types.Result
+ Miso.JSON.Types: instance GHC.Base.Alternative Miso.JSON.Types.Result
+ Miso.JSON.Types: instance GHC.Base.Applicative Miso.JSON.Types.Result
+ Miso.JSON.Types: instance GHC.Base.Functor Miso.JSON.Types.Result
+ Miso.JSON.Types: instance GHC.Base.Monad Miso.JSON.Types.Result
+ Miso.JSON.Types: instance GHC.Base.MonadPlus Miso.JSON.Types.Result
+ Miso.JSON.Types: instance GHC.Base.Monoid (Miso.JSON.Types.Result a)
+ Miso.JSON.Types: instance GHC.Base.Semigroup (Miso.JSON.Types.Result a)
+ Miso.JSON.Types: instance GHC.Classes.Eq Miso.JSON.Types.Value
+ Miso.JSON.Types: instance GHC.Classes.Eq a => GHC.Classes.Eq (Miso.JSON.Types.Result a)
+ Miso.JSON.Types: instance GHC.Show.Show Miso.JSON.Types.Value
+ Miso.JSON.Types: instance GHC.Show.Show a => GHC.Show.Show (Miso.JSON.Types.Result a)
+ Miso.JSON.Types: type Object = Map MisoString Value
+ Miso.JSON.Types: type Pair = (MisoString, Value)
+ Miso.Lens: (%=) :: MonadState record m => Lens record field -> (field -> field) -> m ()
+ Miso.Lens: (%?=) :: MonadState record m => Lens record (Maybe field) -> (field -> field) -> m ()
+ Miso.Lens: (%~) :: Lens record field -> (field -> field) -> record -> record
+ Miso.Lens: (&) :: a -> (a -> b) -> b
+ Miso.Lens: (*=) :: (MonadState record m, Num field) => Lens record field -> field -> m ()
+ Miso.Lens: (*~) :: Num field => Lens record field -> field -> record -> record
+ Miso.Lens: (+=) :: (MonadState record m, Num field) => Lens record field -> field -> m ()
+ Miso.Lens: (+~) :: Num field => Lens record field -> field -> record -> record
+ Miso.Lens: (-=) :: (MonadState record m, Num field) => Lens record field -> field -> m ()
+ Miso.Lens: (-~) :: Num field => Lens record field -> field -> record -> record
+ Miso.Lens: (.=) :: MonadState record m => Lens record field -> field -> m ()
+ Miso.Lens: (.~) :: Lens record field -> field -> record -> record
+ Miso.Lens: (//=) :: (MonadState record m, Fractional field) => Lens record field -> field -> m ()
+ Miso.Lens: (//~) :: Fractional field => Lens record field -> field -> record -> record
+ Miso.Lens: (<%=) :: MonadState record m => Lens record field -> (field -> field) -> m field
+ Miso.Lens: (<&>) :: Functor f => f a -> (a -> b) -> f b
+ Miso.Lens: (<.=) :: MonadState record m => Lens record field -> field -> m field
+ Miso.Lens: (<<%=) :: MonadState record m => Lens record field -> (field -> field) -> m field
+ Miso.Lens: (<<.=) :: MonadState record m => Lens record field -> field -> m field
+ Miso.Lens: (<>~) :: Monoid field => Lens record field -> field -> record -> record
+ Miso.Lens: (<?=) :: MonadState record m => Lens record (Maybe field) -> field -> m field
+ Miso.Lens: (<~) :: MonadState record m => Lens record field -> m field -> m ()
+ Miso.Lens: (?=) :: MonadState record m => Lens record (Maybe field) -> field -> m ()
+ Miso.Lens: (?~) :: Lens record (Maybe field) -> field -> record -> record
+ Miso.Lens: (^.) :: record -> Lens record field -> field
+ Miso.Lens: (^?) :: s -> Prism s a -> Maybe a
+ Miso.Lens: -- | Indexed value of the container
+ Miso.Lens: Lens :: (record -> field) -> (field -> record -> record) -> LensCore field record
+ Miso.Lens: Prism :: (a -> s) -> (s -> Maybe a) -> Prism s a
+ Miso.Lens: [_down] :: Prism s a -> s -> Maybe a
+ Miso.Lens: [_get] :: LensCore field record -> record -> field
+ Miso.Lens: [_set] :: LensCore field record -> field -> record -> record
+ Miso.Lens: [_up] :: Prism s a -> a -> s
+ Miso.Lens: _1 :: Lens (a, b) a
+ Miso.Lens: _2 :: Lens (a, b) b
+ Miso.Lens: _Just :: Prism (Maybe a) a
+ Miso.Lens: _Left :: Prism (Either a b) a
+ Miso.Lens: _Nothing :: Prism (Maybe a) a
+ Miso.Lens: _Right :: Prism (Either a b) b
+ Miso.Lens: _id :: Lens a a
+ Miso.Lens: assign :: MonadState record m => Lens record field -> field -> m ()
+ Miso.Lens: at :: At at => Index at -> Lens at (Maybe (IxValue at))
+ Miso.Lens: class At at where {
+ Miso.Lens: compose :: Category cat => cat a b -> cat b c -> cat a c
+ Miso.Lens: data LensCore field record
+ Miso.Lens: data Prism s a
+ Miso.Lens: fromVL :: Lens' record field -> Lens record field
+ Miso.Lens: infix 4 ?=
+ Miso.Lens: infixl 1 <&>
+ Miso.Lens: infixl 8 ^?
+ Miso.Lens: infixr 2 <~
+ Miso.Lens: infixr 4 <>~
+ Miso.Lens: instance Control.Category.Category Miso.Lens.LensCore
+ Miso.Lens: instance GHC.Classes.Ord k => Miso.Lens.At (Data.Map.Internal.Map k v)
+ Miso.Lens: instance GHC.Classes.Ord k => Miso.Lens.At (Data.Set.Internal.Set k)
+ Miso.Lens: instance Miso.Lens.At (Data.IntMap.Internal.IntMap v)
+ Miso.Lens: instance Miso.Lens.At Data.IntSet.Internal.IntSet
+ Miso.Lens: instance Miso.Lens.At [a]
+ Miso.Lens: lens :: (record -> field) -> (record -> field -> record) -> Lens record field
+ Miso.Lens: modifying :: MonadState record m => Lens record field -> (field -> field) -> m ()
+ Miso.Lens: over :: Lens record field -> (field -> field) -> record -> record
+ Miso.Lens: preuse :: MonadState s m => Prism s a -> m (Maybe a)
+ Miso.Lens: preview :: MonadReader r m => Prism r a -> m (Maybe a)
+ Miso.Lens: prism :: (a -> s) -> (s -> Maybe a) -> Prism s a
+ Miso.Lens: review :: Prism s a -> a -> s
+ Miso.Lens: set :: Lens record field -> field -> record -> record
+ Miso.Lens: this :: Lens a a
+ Miso.Lens: toVL :: Lens record field -> Lens' record field
+ Miso.Lens: type Index at;
+ Miso.Lens: type IxValue at;
+ Miso.Lens: type Lens s a = LensCore a s
+ Miso.Lens: type Lens' s a = forall (f :: Type -> Type). Functor f => a -> f a -> s -> f s
+ Miso.Lens: use :: MonadState record m => Lens record field -> m field
+ Miso.Lens: view :: MonadReader record m => Lens record field -> m field
+ Miso.Lens: }
+ Miso.Mathml.Element: annotationXml_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: annotation_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: math_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: merror_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mfenced_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mfrac_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mi_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mmultiscripts_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mn_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mo_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mover_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mpadded_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mphantom_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mprescripts_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mroot_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mrow_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: ms_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mspace_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: msqrt_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mstyle_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: msub_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: msubsup_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: msup_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mtable_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mtd_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mtext_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: mtr_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: munder_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: munderover_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Element: semantics_ :: [Attribute action] -> [View model action] -> View model action
+ Miso.Mathml.Property: accent_ :: Bool -> Attribute action
+ Miso.Mathml.Property: accentunder_ :: Bool -> Attribute action
+ Miso.Mathml.Property: align_ :: Bool -> Attribute action
+ Miso.Mathml.Property: close_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: columnalign_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: columnlines_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: columnspacing_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: columnspan_ :: Int -> Attribute action
+ Miso.Mathml.Property: depth_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: dir_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: display_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: displaystyle_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: fence_ :: Bool -> Attribute action
+ Miso.Mathml.Property: frame_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: framespacing_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: height_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: href_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: id_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: linethickness_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: lspace_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: mathbackground_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: mathcolor_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: mathsize_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: mathvariant_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: maxsize_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: minsize_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: movablelimits_ :: Bool -> Attribute action
+ Miso.Mathml.Property: notation_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: open_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: rowalign_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: rowlines_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: rowspacing_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: rowspan_ :: Int -> Attribute action
+ Miso.Mathml.Property: rspace_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: scriptlevel_ :: Int -> Attribute action
+ Miso.Mathml.Property: separator_ :: Bool -> Attribute action
+ Miso.Mathml.Property: stretchy_ :: Bool -> Attribute action
+ Miso.Mathml.Property: symmetric_ :: Bool -> Attribute action
+ Miso.Mathml.Property: voffset_ :: MisoString -> Attribute action
+ Miso.Mathml.Property: width_ :: MisoString -> Attribute action
+ Miso.Media: HAVE_CURRENT_DATA :: ReadyState
+ Miso.Media: HAVE_ENOUGH_DATA :: ReadyState
+ Miso.Media: HAVE_FUTURE_DATA :: ReadyState
+ Miso.Media: HAVE_METADATA :: ReadyState
+ Miso.Media: HAVE_NOTHING :: ReadyState
+ Miso.Media: Media :: JSVal -> Media
+ Miso.Media: NETWORK_EMPTY :: NetworkState
+ Miso.Media: NETWORK_IDLE :: NetworkState
+ Miso.Media: NETWORK_LOADING :: NetworkState
+ Miso.Media: NETWORK_NO_SOURCE :: NetworkState
+ Miso.Media: autoplay :: Media -> IO Bool
+ Miso.Media: canPlayType :: Media -> IO MisoString
+ Miso.Media: controls :: Media -> IO Bool
+ Miso.Media: currentSrc :: Media -> IO MisoString
+ Miso.Media: currentTime :: Media -> IO Double
+ Miso.Media: data NetworkState
+ Miso.Media: data ReadyState
+ Miso.Media: defaultMuted :: Media -> IO Bool
+ Miso.Media: defaultPlaybackRate :: Media -> IO Double
+ Miso.Media: duration :: Media -> IO Double
+ Miso.Media: ended :: Media -> IO Bool
+ Miso.Media: instance GHC.Classes.Eq Miso.Media.Media
+ Miso.Media: instance GHC.Classes.Eq Miso.Media.NetworkState
+ Miso.Media: instance GHC.Classes.Eq Miso.Media.ReadyState
+ Miso.Media: instance GHC.Enum.Enum Miso.Media.NetworkState
+ Miso.Media: instance GHC.Enum.Enum Miso.Media.ReadyState
+ Miso.Media: instance GHC.Show.Show Miso.Media.NetworkState
+ Miso.Media: instance GHC.Show.Show Miso.Media.ReadyState
+ Miso.Media: instance Miso.DSL.ToJSVal Miso.Media.Media
+ Miso.Media: load :: Media -> IO ()
+ Miso.Media: loop :: Media -> IO Bool
+ Miso.Media: mediaEvents :: Events
+ Miso.Media: mediaGroup :: Media -> IO MisoString
+ Miso.Media: muted :: Media -> IO Bool
+ Miso.Media: networkState :: Media -> IO NetworkState
+ Miso.Media: newtype Media
+ Miso.Media: pause :: Media -> IO ()
+ Miso.Media: paused :: Media -> IO Bool
+ Miso.Media: play :: Media -> IO ()
+ Miso.Media: playbackRate :: Media -> IO Double
+ Miso.Media: poster :: Media -> IO MisoString
+ Miso.Media: preload :: Media -> IO MisoString
+ Miso.Media: readyState :: Media -> IO ReadyState
+ Miso.Media: seeking :: Media -> IO Bool
+ Miso.Media: srcObject :: Stream -> Media -> IO ()
+ Miso.Media: type Stream = JSVal
+ Miso.Media: videoHeight :: Media -> IO Int
+ Miso.Media: videoWidth :: Media -> IO Int
+ Miso.Media: volume :: Media -> IO Double
+ Miso.Navigator: Geolocation :: Double -> Double -> Double -> Geolocation
+ Miso.Navigator: GeolocationError :: GeolocationErrorCode -> MisoString -> GeolocationError
+ Miso.Navigator: PERMISSION_DENIED :: GeolocationErrorCode
+ Miso.Navigator: POSITION_UNAVAILABLE :: GeolocationErrorCode
+ Miso.Navigator: TIMEOUT :: GeolocationErrorCode
+ Miso.Navigator: UserMedia :: Bool -> Bool -> UserMedia
+ Miso.Navigator: [accuracy] :: Geolocation -> Double
+ Miso.Navigator: [audio] :: UserMedia -> Bool
+ Miso.Navigator: [latitude] :: Geolocation -> Double
+ Miso.Navigator: [longitude] :: Geolocation -> Double
+ Miso.Navigator: [video] :: UserMedia -> Bool
+ Miso.Navigator: copyClipboard :: MisoString -> action -> (JSVal -> action) -> Effect parent model action
+ Miso.Navigator: data Geolocation
+ Miso.Navigator: data GeolocationError
+ Miso.Navigator: data GeolocationErrorCode
+ Miso.Navigator: data UserMedia
+ Miso.Navigator: geolocation :: (Geolocation -> action) -> (GeolocationError -> action) -> Effect parent model action
+ Miso.Navigator: getUserMedia :: UserMedia -> (Stream -> action) -> (JSVal -> action) -> Effect parent model action
+ Miso.Navigator: instance GHC.Classes.Eq Miso.Navigator.Geolocation
+ Miso.Navigator: instance GHC.Classes.Eq Miso.Navigator.GeolocationError
+ Miso.Navigator: instance GHC.Classes.Eq Miso.Navigator.GeolocationErrorCode
+ Miso.Navigator: instance GHC.Classes.Eq Miso.Navigator.UserMedia
+ Miso.Navigator: instance GHC.Enum.Enum Miso.Navigator.GeolocationErrorCode
+ Miso.Navigator: instance GHC.Show.Show Miso.Navigator.Geolocation
+ Miso.Navigator: instance GHC.Show.Show Miso.Navigator.GeolocationError
+ Miso.Navigator: instance GHC.Show.Show Miso.Navigator.GeolocationErrorCode
+ Miso.Navigator: instance GHC.Show.Show Miso.Navigator.UserMedia
+ Miso.Navigator: instance Miso.DSL.FromJSVal Miso.Navigator.Geolocation
+ Miso.Navigator: instance Miso.DSL.FromJSVal Miso.Navigator.GeolocationError
+ Miso.Navigator: instance Miso.DSL.FromJSVal Miso.Navigator.GeolocationErrorCode
+ Miso.Navigator: isOnLine :: (Bool -> action) -> Effect parent model action
+ Miso.Navigator: type Stream = JSVal
+ Miso.Navigator: userMedia :: UserMedia
+ Miso.Prelude: ($!) :: (a -> b) -> a -> b
+ Miso.Prelude: ($) :: (a -> b) -> a -> b
+ Miso.Prelude: (&&) :: Bool -> Bool -> Bool
+ Miso.Prelude: (*) :: Num a => a -> a -> a
+ Miso.Prelude: (**) :: Floating a => a -> a -> a
+ Miso.Prelude: (*>) :: Applicative f => f a -> f b -> f b
+ Miso.Prelude: (+) :: Num a => a -> a -> a
+ Miso.Prelude: (++) :: [a] -> [a] -> [a]
+ Miso.Prelude: (-) :: Num a => a -> a -> a
+ Miso.Prelude: (.) :: forall (b :: k) (c :: k) (a :: k). Category cat => cat b c -> cat a b -> cat a c
+ Miso.Prelude: (/) :: Fractional a => a -> a -> a
+ Miso.Prelude: (/=) :: Eq a => a -> a -> Bool
+ Miso.Prelude: (<$) :: Functor f => a -> f b -> f a
+ Miso.Prelude: (<$>) :: Functor f => (a -> b) -> f a -> f b
+ Miso.Prelude: (<) :: Ord a => a -> a -> Bool
+ Miso.Prelude: (<*) :: Applicative f => f a -> f b -> f a
+ Miso.Prelude: (<*>) :: Applicative f => f (a -> b) -> f a -> f b
+ Miso.Prelude: (<=) :: Ord a => a -> a -> Bool
+ Miso.Prelude: (<>) :: Semigroup a => a -> a -> a
+ Miso.Prelude: (=<<) :: Monad m => (a -> m b) -> m a -> m b
+ Miso.Prelude: (==) :: Eq a => a -> a -> Bool
+ Miso.Prelude: (>) :: Ord a => a -> a -> Bool
+ Miso.Prelude: (>=) :: Ord a => a -> a -> Bool
+ Miso.Prelude: (>>) :: Monad m => m a -> m b -> m b
+ Miso.Prelude: (>>=) :: Monad m => m a -> (a -> m b) -> m b
+ Miso.Prelude: (^) :: (Num a, Integral b) => a -> b -> a
+ Miso.Prelude: (^^) :: (Fractional a, Integral b) => a -> b -> a
+ Miso.Prelude: (||) :: Bool -> Bool -> Bool
+ Miso.Prelude: EQ :: Ordering
+ Miso.Prelude: False :: Bool
+ Miso.Prelude: GT :: Ordering
+ Miso.Prelude: Just :: a -> Maybe a
+ Miso.Prelude: LT :: Ordering
+ Miso.Prelude: Left :: a -> Either a b
+ Miso.Prelude: Nothing :: Maybe a
+ Miso.Prelude: Right :: b -> Either a b
+ Miso.Prelude: True :: Bool
+ Miso.Prelude: abs :: Num a => a -> a
+ Miso.Prelude: acos :: Floating a => a -> a
+ Miso.Prelude: acosh :: Floating a => a -> a
+ Miso.Prelude: all :: Foldable t => (a -> Bool) -> t a -> Bool
+ Miso.Prelude: and :: Foldable t => t Bool -> Bool
+ Miso.Prelude: any :: Foldable t => (a -> Bool) -> t a -> Bool
+ Miso.Prelude: appendFile :: FilePath -> String -> IO ()
+ Miso.Prelude: asTypeOf :: a -> a -> a
+ Miso.Prelude: asin :: Floating a => a -> a
+ Miso.Prelude: asinh :: Floating a => a -> a
+ Miso.Prelude: atan :: Floating a => a -> a
+ Miso.Prelude: atan2 :: RealFloat a => a -> a -> a
+ Miso.Prelude: atanh :: Floating a => a -> a
+ Miso.Prelude: break :: (a -> Bool) -> [a] -> ([a], [a])
+ Miso.Prelude: ceiling :: (RealFrac a, Integral b) => a -> b
+ Miso.Prelude: class a ~# b => (a :: k) ~ (b :: k)
+ Miso.Prelude: class Functor f => Applicative (f :: Type -> Type)
+ Miso.Prelude: class Bounded a
+ Miso.Prelude: class Enum a
+ Miso.Prelude: class Eq a
+ Miso.Prelude: class Fractional a => Floating a
+ Miso.Prelude: class Foldable (t :: Type -> Type)
+ Miso.Prelude: class Num a => Fractional a
+ Miso.Prelude: class Functor (f :: Type -> Type)
+ Miso.Prelude: class (Real a, Enum a) => Integral a
+ Miso.Prelude: class Applicative m => Monad (m :: Type -> Type)
+ Miso.Prelude: class Monad m => MonadFail (m :: Type -> Type)
+ Miso.Prelude: class Semigroup a => Monoid a
+ Miso.Prelude: class Num a
+ Miso.Prelude: class Eq a => Ord a
+ Miso.Prelude: class Read a
+ Miso.Prelude: class (Num a, Ord a) => Real a
+ Miso.Prelude: class (RealFrac a, Floating a) => RealFloat a
+ Miso.Prelude: class (Real a, Fractional a) => RealFrac a
+ Miso.Prelude: class Semigroup a
+ Miso.Prelude: class Show a
+ Miso.Prelude: class (Functor t, Foldable t) => Traversable (t :: Type -> Type)
+ Miso.Prelude: compare :: Ord a => a -> a -> Ordering
+ Miso.Prelude: concat :: Foldable t => t [a] -> [a]
+ Miso.Prelude: concatMap :: Foldable t => (a -> [b]) -> t a -> [b]
+ Miso.Prelude: const :: a -> b -> a
+ Miso.Prelude: cos :: Floating a => a -> a
+ Miso.Prelude: cosh :: Floating a => a -> a
+ Miso.Prelude: curry :: ((a, b) -> c) -> a -> b -> c
+ Miso.Prelude: cycle :: HasCallStack => [a] -> [a]
+ Miso.Prelude: data Bool
+ Miso.Prelude: data Char
+ Miso.Prelude: data Double
+ Miso.Prelude: data Either a b
+ Miso.Prelude: data Float
+ Miso.Prelude: data IO a
+ Miso.Prelude: data Int
+ Miso.Prelude: data Integer
+ Miso.Prelude: data Maybe a
+ Miso.Prelude: data Ordering
+ Miso.Prelude: data Word
+ Miso.Prelude: decodeFloat :: RealFloat a => a -> (Integer, Int)
+ Miso.Prelude: div :: Integral a => a -> a -> a
+ Miso.Prelude: divMod :: Integral a => a -> a -> (a, a)
+ Miso.Prelude: drop :: Int -> [a] -> [a]
+ Miso.Prelude: dropWhile :: (a -> Bool) -> [a] -> [a]
+ Miso.Prelude: either :: (a -> c) -> (b -> c) -> Either a b -> c
+ Miso.Prelude: elem :: (Foldable t, Eq a) => a -> t a -> Bool
+ Miso.Prelude: encodeFloat :: RealFloat a => Integer -> Int -> a
+ Miso.Prelude: enumFrom :: Enum a => a -> [a]
+ Miso.Prelude: enumFromThen :: Enum a => a -> a -> [a]
+ Miso.Prelude: enumFromThenTo :: Enum a => a -> a -> a -> [a]
+ Miso.Prelude: enumFromTo :: Enum a => a -> a -> [a]
+ Miso.Prelude: error :: HasCallStack => [Char] -> a
+ Miso.Prelude: errorWithoutStackTrace :: [Char] -> a
+ Miso.Prelude: even :: Integral a => a -> Bool
+ Miso.Prelude: exp :: Floating a => a -> a
+ Miso.Prelude: exponent :: RealFloat a => a -> Int
+ Miso.Prelude: fail :: MonadFail m => String -> m a
+ Miso.Prelude: filter :: (a -> Bool) -> [a] -> [a]
+ Miso.Prelude: flip :: (a -> b -> c) -> b -> a -> c
+ Miso.Prelude: floatDigits :: RealFloat a => a -> Int
+ Miso.Prelude: floatRadix :: RealFloat a => a -> Integer
+ Miso.Prelude: floatRange :: RealFloat a => a -> (Int, Int)
+ Miso.Prelude: floor :: (RealFrac a, Integral b) => a -> b
+ Miso.Prelude: fmap :: Functor f => (a -> b) -> f a -> f b
+ Miso.Prelude: foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
+ Miso.Prelude: foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
+ Miso.Prelude: foldl1 :: Foldable t => (a -> a -> a) -> t a -> a
+ Miso.Prelude: foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
+ Miso.Prelude: foldr1 :: Foldable t => (a -> a -> a) -> t a -> a
+ Miso.Prelude: fromEnum :: Enum a => a -> Int
+ Miso.Prelude: fromInteger :: Num a => Integer -> a
+ Miso.Prelude: fromIntegral :: (Integral a, Num b) => a -> b
+ Miso.Prelude: fromRational :: Fractional a => Rational -> a
+ Miso.Prelude: fst :: (a, b) -> a
+ Miso.Prelude: gcd :: Integral a => a -> a -> a
+ Miso.Prelude: getChar :: IO Char
+ Miso.Prelude: getContents :: IO String
+ Miso.Prelude: getLine :: IO String
+ Miso.Prelude: head :: HasCallStack => [a] -> a
+ Miso.Prelude: id :: a -> a
+ Miso.Prelude: infix 4 `notElem`
+ Miso.Prelude: infixl 1 >>
+ Miso.Prelude: infixl 4 <*
+ Miso.Prelude: infixl 6 +
+ Miso.Prelude: infixl 7 /
+ Miso.Prelude: infixr 0 $!
+ Miso.Prelude: infixr 1 =<<
+ Miso.Prelude: infixr 2 ||
+ Miso.Prelude: infixr 3 &&
+ Miso.Prelude: infixr 5 ++
+ Miso.Prelude: infixr 6 <>
+ Miso.Prelude: infixr 8 ^^
+ Miso.Prelude: infixr 9 .
+ Miso.Prelude: init :: HasCallStack => [a] -> [a]
+ Miso.Prelude: interact :: (String -> String) -> IO ()
+ Miso.Prelude: ioError :: IOError -> IO a
+ Miso.Prelude: isDenormalized :: RealFloat a => a -> Bool
+ Miso.Prelude: isIEEE :: RealFloat a => a -> Bool
+ Miso.Prelude: isInfinite :: RealFloat a => a -> Bool
+ Miso.Prelude: isNaN :: RealFloat a => a -> Bool
+ Miso.Prelude: isNegativeZero :: RealFloat a => a -> Bool
+ Miso.Prelude: iterate :: (a -> a) -> a -> [a]
+ Miso.Prelude: last :: HasCallStack => [a] -> a
+ Miso.Prelude: lcm :: Integral a => a -> a -> a
+ Miso.Prelude: length :: Foldable t => t a -> Int
+ Miso.Prelude: lex :: ReadS String
+ Miso.Prelude: liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
+ Miso.Prelude: lines :: String -> [String]
+ Miso.Prelude: log :: Floating a => a -> a
+ Miso.Prelude: logBase :: Floating a => a -> a -> a
+ Miso.Prelude: lookup :: Eq a => a -> [(a, b)] -> Maybe b
+ Miso.Prelude: map :: (a -> b) -> [a] -> [b]
+ Miso.Prelude: mapM :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)
+ Miso.Prelude: mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m ()
+ Miso.Prelude: mappend :: Monoid a => a -> a -> a
+ Miso.Prelude: max :: Ord a => a -> a -> a
+ Miso.Prelude: maxBound :: Bounded a => a
+ Miso.Prelude: maximum :: (Foldable t, Ord a) => t a -> a
+ Miso.Prelude: maybe :: b -> (a -> b) -> Maybe a -> b
+ Miso.Prelude: mconcat :: Monoid a => [a] -> a
+ Miso.Prelude: mempty :: Monoid a => a
+ Miso.Prelude: min :: Ord a => a -> a -> a
+ Miso.Prelude: minBound :: Bounded a => a
+ Miso.Prelude: minimum :: (Foldable t, Ord a) => t a -> a
+ Miso.Prelude: mod :: Integral a => a -> a -> a
+ Miso.Prelude: negate :: Num a => a -> a
+ Miso.Prelude: not :: Bool -> Bool
+ Miso.Prelude: notElem :: (Foldable t, Eq a) => a -> t a -> Bool
+ Miso.Prelude: null :: Foldable t => t a -> Bool
+ Miso.Prelude: odd :: Integral a => a -> Bool
+ Miso.Prelude: or :: Foldable t => t Bool -> Bool
+ Miso.Prelude: otherwise :: Bool
+ Miso.Prelude: pi :: Floating a => a
+ Miso.Prelude: pred :: Enum a => a -> a
+ Miso.Prelude: print :: Show a => a -> IO ()
+ Miso.Prelude: product :: (Foldable t, Num a) => t a -> a
+ Miso.Prelude: properFraction :: (RealFrac a, Integral b) => a -> (b, a)
+ Miso.Prelude: pure :: Applicative f => a -> f a
+ Miso.Prelude: putChar :: Char -> IO ()
+ Miso.Prelude: putStr :: String -> IO ()
+ Miso.Prelude: putStrLn :: String -> IO ()
+ Miso.Prelude: quot :: Integral a => a -> a -> a
+ Miso.Prelude: quotRem :: Integral a => a -> a -> (a, a)
+ Miso.Prelude: read :: Read a => String -> a
+ Miso.Prelude: readFile :: FilePath -> IO String
+ Miso.Prelude: readIO :: Read a => String -> IO a
+ Miso.Prelude: readList :: Read a => ReadS [a]
+ Miso.Prelude: readLn :: Read a => IO a
+ Miso.Prelude: readParen :: Bool -> ReadS a -> ReadS a
+ Miso.Prelude: reads :: Read a => ReadS a
+ Miso.Prelude: readsPrec :: Read a => Int -> ReadS a
+ Miso.Prelude: realToFrac :: (Real a, Fractional b) => a -> b
+ Miso.Prelude: recip :: Fractional a => a -> a
+ Miso.Prelude: rem :: Integral a => a -> a -> a
+ Miso.Prelude: repeat :: a -> [a]
+ Miso.Prelude: replicate :: Int -> a -> [a]
+ Miso.Prelude: return :: Monad m => a -> m a
+ Miso.Prelude: reverse :: [a] -> [a]
+ Miso.Prelude: round :: (RealFrac a, Integral b) => a -> b
+ Miso.Prelude: scaleFloat :: RealFloat a => Int -> a -> a
+ Miso.Prelude: scanl :: (b -> a -> b) -> b -> [a] -> [b]
+ Miso.Prelude: scanl1 :: (a -> a -> a) -> [a] -> [a]
+ Miso.Prelude: scanr :: (a -> b -> b) -> b -> [a] -> [b]
+ Miso.Prelude: scanr1 :: (a -> a -> a) -> [a] -> [a]
+ Miso.Prelude: seq :: a -> b -> b
+ Miso.Prelude: sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
+ Miso.Prelude: sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
+ Miso.Prelude: sequence_ :: (Foldable t, Monad m) => t (m a) -> m ()
+ Miso.Prelude: show :: Show a => a -> String
+ Miso.Prelude: showChar :: Char -> ShowS
+ Miso.Prelude: showList :: Show a => [a] -> ShowS
+ Miso.Prelude: showParen :: Bool -> ShowS -> ShowS
+ Miso.Prelude: showString :: String -> ShowS
+ Miso.Prelude: shows :: Show a => a -> ShowS
+ Miso.Prelude: showsPrec :: Show a => Int -> a -> ShowS
+ Miso.Prelude: significand :: RealFloat a => a -> a
+ Miso.Prelude: signum :: Num a => a -> a
+ Miso.Prelude: sin :: Floating a => a -> a
+ Miso.Prelude: sinh :: Floating a => a -> a
+ Miso.Prelude: snd :: (a, b) -> b
+ Miso.Prelude: span :: (a -> Bool) -> [a] -> ([a], [a])
+ Miso.Prelude: splitAt :: Int -> [a] -> ([a], [a])
+ Miso.Prelude: sqrt :: Floating a => a -> a
+ Miso.Prelude: subtract :: Num a => a -> a -> a
+ Miso.Prelude: succ :: Enum a => a -> a
+ Miso.Prelude: sum :: (Foldable t, Num a) => t a -> a
+ Miso.Prelude: tail :: HasCallStack => [a] -> [a]
+ Miso.Prelude: take :: Int -> [a] -> [a]
+ Miso.Prelude: takeWhile :: (a -> Bool) -> [a] -> [a]
+ Miso.Prelude: tan :: Floating a => a -> a
+ Miso.Prelude: tanh :: Floating a => a -> a
+ Miso.Prelude: toEnum :: Enum a => Int -> a
+ Miso.Prelude: toInteger :: Integral a => a -> Integer
+ Miso.Prelude: toRational :: Real a => a -> Rational
+ Miso.Prelude: traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
+ Miso.Prelude: truncate :: (RealFrac a, Integral b) => a -> b
+ Miso.Prelude: type FilePath = String
+ Miso.Prelude: type IOError = IOException
+ Miso.Prelude: type Rational = Ratio Integer
+ Miso.Prelude: type ReadS a = String -> [(a, String)]
+ Miso.Prelude: type ShowS = String -> String
+ Miso.Prelude: type String = [Char]
+ Miso.Prelude: uncurry :: (a -> b -> c) -> (a, b) -> c
+ Miso.Prelude: undefined :: HasCallStack => a
+ Miso.Prelude: unlines :: [String] -> String
+ Miso.Prelude: until :: (a -> Bool) -> (a -> a) -> a -> a
+ Miso.Prelude: unwords :: [String] -> String
+ Miso.Prelude: unzip :: [(a, b)] -> ([a], [b])
+ Miso.Prelude: unzip3 :: [(a, b, c)] -> ([a], [b], [c])
+ Miso.Prelude: userError :: String -> IOError
+ Miso.Prelude: words :: String -> [String]
+ Miso.Prelude: writeFile :: FilePath -> String -> IO ()
+ Miso.Prelude: zip :: [a] -> [b] -> [(a, b)]
+ Miso.Prelude: zip3 :: [a] -> [b] -> [c] -> [(a, b, c)]
+ Miso.Prelude: zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
+ Miso.Prelude: zipWith3 :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
+ Miso.Property: boolProp :: MisoString -> Bool -> Attribute action
+ Miso.Property: classList :: [MisoString] -> Attribute action
+ Miso.Property: doubleProp :: MisoString -> Double -> Attribute action
+ Miso.Property: intProp :: MisoString -> Int -> Attribute action
+ Miso.Property: integerProp :: MisoString -> Integer -> Attribute action
+ Miso.Property: keyProp :: ToKey key => key -> Attribute action
+ Miso.Property: key_ :: ToKey key => key -> Attribute action
+ Miso.Property: objectProp :: MisoString -> Object -> Attribute action
+ Miso.Property: prop :: ToJSON a => MisoString -> a -> Attribute action
+ Miso.Property: stringProp :: MisoString -> String -> Attribute action
+ Miso.Property: textProp :: MisoString -> MisoString -> Attribute action
+ Miso.PubSub: data Topic a
+ Miso.PubSub: publish :: ToJSON message => Topic message -> message -> IO ()
+ Miso.PubSub: subscribe :: FromJSON message => Topic message -> (message -> action) -> (MisoString -> action) -> Effect parent model action
+ Miso.PubSub: topic :: MisoString -> Topic a
+ Miso.PubSub: unsubscribe :: Topic message -> Effect parent model action
+ Miso.Random: StdGen :: Function -> StdGen
+ Miso.Random: getStdGen :: IO StdGen
+ Miso.Random: globalStdGen :: IORef StdGen
+ Miso.Random: mkStdGen :: Seed -> StdGen
+ Miso.Random: newStdGen :: IO StdGen
+ Miso.Random: newtype StdGen
+ Miso.Random: next :: StdGen -> (Double, StdGen)
+ Miso.Random: replicateRM :: Int -> IO [Double]
+ Miso.Random: setStdGen :: StdGen -> IO ()
+ Miso.Random: type Seed = Int
+ Miso.Reload: live :: Eq model => Events -> App model action -> IO ()
+ Miso.Reload: reload :: Eq model => Events -> App model action -> IO ()
+ Miso.Router: ($dmfromRoute) :: (Router route, Generic route, GRouter (Rep route)) => route -> [Token]
+ Miso.Router: ($dmrouteParser) :: (Router route, Generic route, GRouter (Rep route)) => RouteParser route
+ Miso.Router: AmbiguousParse :: MisoString -> [Token] -> RoutingError
+ Miso.Router: Capture :: a -> Capture (sym :: k) a
+ Miso.Router: CaptureOrPathToken :: MisoString -> Token
+ Miso.Router: FragmentToken :: MisoString -> Token
+ Miso.Router: IndexToken :: Token
+ Miso.Router: LexError :: MisoString -> MisoString -> RoutingError
+ Miso.Router: LexErrorEOF :: MisoString -> RoutingError
+ Miso.Router: NoParses :: MisoString -> RoutingError
+ Miso.Router: ParseError :: MisoString -> [Token] -> RoutingError
+ Miso.Router: Path :: MisoString -> Path (path :: Symbol)
+ Miso.Router: QueryFlag :: Bool -> QueryFlag (path :: Symbol)
+ Miso.Router: QueryParam :: Maybe a -> QueryParam (path :: Symbol) a
+ Miso.Router: QueryParamToken :: MisoString -> Maybe MisoString -> Token
+ Miso.Router: QueryParamTokens :: [(MisoString, Maybe MisoString)] -> Token
+ Miso.Router: URI :: MisoString -> MisoString -> Map MisoString (Maybe MisoString) -> URI
+ Miso.Router: [uriFragment] :: URI -> MisoString
+ Miso.Router: [uriPath] :: URI -> MisoString
+ Miso.Router: [uriQueryString] :: URI -> Map MisoString (Maybe MisoString)
+ Miso.Router: capture :: FromMisoString value => RouteParser value
+ Miso.Router: class GRouter (f :: k -> Type)
+ Miso.Router: class Router route
+ Miso.Router: data Token
+ Miso.Router: data URI
+ Miso.Router: dumpURI :: Router route => route -> MisoString
+ Miso.Router: emptyURI :: URI
+ Miso.Router: fromRoute :: Router route => route -> [Token]
+ Miso.Router: gFromRoute :: forall (route :: k). GRouter f => f route -> [Token]
+ Miso.Router: gRouteParser :: forall (route :: k). GRouter f => RouteParser (f route)
+ Miso.Router: href_ :: Router route => route -> Attribute action
+ Miso.Router: instance (Miso.String.FromMisoString a, GHC.TypeLits.KnownSymbol path) => Miso.String.FromMisoString (Miso.Router.QueryParam path a)
+ Miso.Router: instance (Miso.String.ToMisoString a, GHC.TypeLits.KnownSymbol path) => Miso.String.ToMisoString (Miso.Router.QueryParam path a)
+ Miso.Router: instance (Miso.String.ToMisoString a, Miso.String.FromMisoString a, GHC.TypeLits.KnownSymbol param) => Miso.Router.GRouter (GHC.Generics.K1 m (Miso.Router.QueryParam param a))
+ Miso.Router: instance Data.String.IsString (Miso.Router.Path path)
+ Miso.Router: instance GHC.Classes.Eq (Miso.Router.Path path)
+ Miso.Router: instance GHC.Classes.Eq (Miso.Router.QueryFlag path)
+ Miso.Router: instance GHC.Classes.Eq Miso.Router.Token
+ Miso.Router: instance GHC.Classes.Eq a => GHC.Classes.Eq (Miso.Router.QueryParam path a)
+ Miso.Router: instance GHC.Show.Show (Miso.Router.Path path)
+ Miso.Router: instance GHC.Show.Show (Miso.Router.QueryFlag path)
+ Miso.Router: instance GHC.Show.Show Miso.Router.Token
+ Miso.Router: instance GHC.Show.Show a => GHC.Show.Show (Miso.Router.QueryParam path a)
+ Miso.Router: instance GHC.TypeLits.KnownSymbol flag => Miso.Router.GRouter (GHC.Generics.K1 m (Miso.Router.QueryFlag flag))
+ Miso.Router: instance GHC.TypeLits.KnownSymbol name => Miso.String.ToMisoString (Miso.Router.QueryFlag name)
+ Miso.Router: instance GHC.TypeLits.KnownSymbol path => Miso.Router.GRouter (GHC.Generics.K1 m (Miso.Router.Path path))
+ Miso.Router: instance Miso.Router.GRouter GHC.Generics.U1
+ Miso.Router: instance Miso.Router.Router a => Miso.Router.GRouter (GHC.Generics.K1 m a)
+ Miso.Router: instance Miso.String.ToMisoString (Miso.Router.Path path)
+ Miso.Router: instance Miso.String.ToMisoString Miso.Router.Token
+ Miso.Router: instance forall k (left :: k -> *) (right :: k -> *). (Miso.Router.GRouter left, Miso.Router.GRouter right) => Miso.Router.GRouter (left GHC.Generics.:*: right)
+ Miso.Router: instance forall k (left :: k -> *) (right :: k -> *). (Miso.Router.GRouter left, Miso.Router.GRouter right) => Miso.Router.GRouter (left GHC.Generics.:+: right)
+ Miso.Router: instance forall k (name :: GHC.Types.Symbol) (next :: k -> *) (x :: GHC.Generics.FixityI) (y :: GHC.Types.Bool). (GHC.TypeLits.KnownSymbol name, Miso.Router.GRouter next) => Miso.Router.GRouter (GHC.Generics.C1 ('GHC.Generics.MetaCons name x y) next)
+ Miso.Router: instance forall k (next :: k -> *) (m :: GHC.Generics.Meta). Miso.Router.GRouter next => Miso.Router.GRouter (GHC.Generics.D1 m next)
+ Miso.Router: instance forall k (next :: k -> *) (m :: GHC.Generics.Meta). Miso.Router.GRouter next => Miso.Router.GRouter (GHC.Generics.S1 m next)
+ Miso.Router: instance forall k (sym :: k) a. GHC.Classes.Eq a => GHC.Classes.Eq (Miso.Router.Capture sym a)
+ Miso.Router: instance forall k (sym :: k) a. GHC.Show.Show a => GHC.Show.Show (Miso.Router.Capture sym a)
+ Miso.Router: instance forall k (sym :: k) a. Miso.String.FromMisoString a => Miso.String.FromMisoString (Miso.Router.Capture sym a)
+ Miso.Router: instance forall k (sym :: k) a. Miso.String.ToMisoString a => Miso.String.ToMisoString (Miso.Router.Capture sym a)
+ Miso.Router: instance forall k1 k2 a m (sym :: k1). (Miso.String.FromMisoString a, Miso.String.ToMisoString a) => Miso.Router.GRouter (GHC.Generics.K1 m (Miso.Router.Capture sym a))
+ Miso.Router: lexTokens :: MisoString -> Either LexerError [Token]
+ Miso.Router: newtype Capture (sym :: k) a
+ Miso.Router: newtype Path (path :: Symbol)
+ Miso.Router: newtype QueryFlag (path :: Symbol)
+ Miso.Router: newtype QueryParam (path :: Symbol) a
+ Miso.Router: parseURI :: MisoString -> Either MisoString URI
+ Miso.Router: path :: MisoString -> RouteParser MisoString
+ Miso.Router: prettyQueryString :: URI -> MisoString
+ Miso.Router: prettyRoute :: Router route => route -> MisoString
+ Miso.Router: prettyURI :: URI -> MisoString
+ Miso.Router: queryFlag :: forall (flag :: Symbol). KnownSymbol flag => RouteParser (QueryFlag flag)
+ Miso.Router: queryParam :: forall (param :: Symbol) a. (FromMisoString a, KnownSymbol param) => RouteParser (QueryParam param a)
+ Miso.Router: routeParser :: Router route => RouteParser route
+ Miso.Router: routes :: [RouteParser route] -> RouteParser route
+ Miso.Router: runRouter :: MisoString -> RouteParser route -> Either RoutingError route
+ Miso.Router: toCapture :: ToMisoString string => string -> Token
+ Miso.Router: toPath :: MisoString -> Token
+ Miso.Router: toQueryParam :: ToMisoString s => MisoString -> s -> Token
+ Miso.Router: toRoute :: Router route => MisoString -> Either RoutingError route
+ Miso.Router: toURI :: Router route => route -> URI
+ Miso.Router: tokensToURI :: [Token] -> URI
+ Miso.Router: type RouteParser = ParserT URI [Token] []
+ Miso.Runtime.Internal: ComponentState :: ComponentId -> ComponentId -> IORef (Map MisoString ThreadId) -> DOMRef -> IORef VTree -> (action -> IO ()) -> model -> Bool -> [DOMRef] -> Events -> [Binding parent model] -> (Value -> Maybe action) -> (model -> IO ()) -> (model -> model -> Bool) -> ([action] -> model -> IntMap (ComponentState parent model action) -> (IntMap (ComponentState parent model action), model, [Schedule action], ComponentIds)) -> Map MisoString (Value -> IO ()) -> ComponentIds -> ComponentState parent model action
+ Miso.Runtime.Internal: [_componentApplyActions] :: ComponentState parent model action -> [action] -> model -> IntMap (ComponentState parent model action) -> (IntMap (ComponentState parent model action), model, [Schedule action], ComponentIds)
+ Miso.Runtime.Internal: [_componentBindings] :: ComponentState parent model action -> [Binding parent model]
+ Miso.Runtime.Internal: [_componentChildren] :: ComponentState parent model action -> ComponentIds
+ Miso.Runtime.Internal: [_componentDOMRef] :: ComponentState parent model action -> DOMRef
+ Miso.Runtime.Internal: [_componentDraw] :: ComponentState parent model action -> model -> IO ()
+ Miso.Runtime.Internal: [_componentEvents] :: ComponentState parent model action -> Events
+ Miso.Runtime.Internal: [_componentId] :: ComponentState parent model action -> ComponentId
+ Miso.Runtime.Internal: [_componentIsDirty] :: ComponentState parent model action -> Bool
+ Miso.Runtime.Internal: [_componentMailbox] :: ComponentState parent model action -> Value -> Maybe action
+ Miso.Runtime.Internal: [_componentModelDirty] :: ComponentState parent model action -> model -> model -> Bool
+ Miso.Runtime.Internal: [_componentModel] :: ComponentState parent model action -> model
+ Miso.Runtime.Internal: [_componentParentId] :: ComponentState parent model action -> ComponentId
+ Miso.Runtime.Internal: [_componentScripts] :: ComponentState parent model action -> [DOMRef]
+ Miso.Runtime.Internal: [_componentSink] :: ComponentState parent model action -> action -> IO ()
+ Miso.Runtime.Internal: [_componentSubThreads] :: ComponentState parent model action -> IORef (Map MisoString ThreadId)
+ Miso.Runtime.Internal: [_componentTopics] :: ComponentState parent model action -> Map MisoString (Value -> IO ())
+ Miso.Runtime.Internal: [_componentVTree] :: ComponentState parent model action -> IORef VTree
+ Miso.Runtime.Internal: componentIds :: IORef Int
+ Miso.Runtime.Internal: components :: IORef (IntMap (ComponentState parent model action))
+ Miso.Runtime.Internal: data ComponentState parent model action
+ Miso.Runtime.Internal: rootComponentId :: ComponentId
+ Miso.State: ask :: MonadReader r m => m r
+ Miso.State: asks :: MonadReader r m => (r -> a) -> m a
+ Miso.State: get :: MonadState s m => m s
+ Miso.State: gets :: MonadState s m => (s -> a) -> m a
+ Miso.State: liftIO :: MonadIO m => IO a -> m a
+ Miso.State: modify :: MonadState s m => (s -> s) -> m ()
+ Miso.State: modify' :: MonadState s m => (s -> s) -> m ()
+ Miso.State: put :: MonadState s m => s -> m ()
+ Miso.State: tell :: MonadWriter w m => w -> m ()
+ Miso.Storage: clearLocalStorage :: IO ()
+ Miso.Storage: clearSessionStorage :: IO ()
+ Miso.Storage: getLocalStorage :: MisoString -> IO (Maybe MisoString)
+ Miso.Storage: getSessionStorage :: MisoString -> IO (Maybe MisoString)
+ Miso.Storage: instance Miso.DSL.ToJSVal Miso.Storage.Storage
+ Miso.Storage: instance Miso.DSL.ToObject Miso.Storage.Storage
+ Miso.Storage: localStorageLength :: IO Int
+ Miso.Storage: removeLocalStorage :: MisoString -> IO ()
+ Miso.Storage: removeSessionStorage :: MisoString -> IO ()
+ Miso.Storage: sessionStorageLength :: IO Int
+ Miso.Storage: setLocalStorage :: MisoString -> MisoString -> IO ()
+ Miso.Storage: setSessionStorage :: MisoString -> MisoString -> IO ()
+ Miso.String: all :: (Char -> Bool) -> Text -> Bool
+ Miso.String: any :: (Char -> Bool) -> Text -> Bool
+ Miso.String: append :: Text -> Text -> Text
+ Miso.String: break :: (Char -> Bool) -> Text -> (Text, Text)
+ Miso.String: breakOn :: HasCallStack => Text -> Text -> (Text, Text)
+ Miso.String: breakOnAll :: HasCallStack => Text -> Text -> [(Text, Text)]
+ Miso.String: breakOnEnd :: HasCallStack => Text -> Text -> (Text, Text)
+ Miso.String: center :: Int -> Char -> Text -> Text
+ Miso.String: chunksOf :: Int -> Text -> [Text]
+ Miso.String: commonPrefixes :: Text -> Text -> Maybe (Text, Text, Text)
+ Miso.String: compareLength :: Text -> Int -> Ordering
+ Miso.String: concat :: [Text] -> Text
+ Miso.String: concatMap :: (Char -> Text) -> Text -> Text
+ Miso.String: cons :: Char -> Text -> Text
+ Miso.String: copy :: Text -> Text
+ Miso.String: count :: HasCallStack => Text -> Text -> Int
+ Miso.String: data Text
+ Miso.String: drop :: Int -> Text -> Text
+ Miso.String: dropAround :: (Char -> Bool) -> Text -> Text
+ Miso.String: dropEnd :: Int -> Text -> Text
+ Miso.String: dropWhile :: (Char -> Bool) -> Text -> Text
+ Miso.String: dropWhileEnd :: (Char -> Bool) -> Text -> Text
+ Miso.String: empty :: Text
+ Miso.String: filter :: (Char -> Bool) -> Text -> Text
+ Miso.String: find :: (Char -> Bool) -> Text -> Maybe Char
+ Miso.String: findIndex :: (Char -> Bool) -> Text -> Maybe Int
+ Miso.String: foldl :: (a -> Char -> a) -> a -> Text -> a
+ Miso.String: foldl' :: (a -> Char -> a) -> a -> Text -> a
+ Miso.String: foldl1 :: HasCallStack => (Char -> Char -> Char) -> Text -> Char
+ Miso.String: foldl1' :: HasCallStack => (Char -> Char -> Char) -> Text -> Char
+ Miso.String: foldr :: (Char -> a -> a) -> a -> Text -> a
+ Miso.String: foldr' :: (Char -> a -> a) -> a -> Text -> a
+ Miso.String: foldr1 :: HasCallStack => (Char -> Char -> Char) -> Text -> Char
+ Miso.String: group :: Text -> [Text]
+ Miso.String: groupBy :: (Char -> Char -> Bool) -> Text -> [Text]
+ Miso.String: head :: HasCallStack => Text -> Char
+ Miso.String: index :: HasCallStack => Text -> Int -> Char
+ Miso.String: infixr 5 `cons`
+ Miso.String: init :: HasCallStack => Text -> Text
+ Miso.String: inits :: Text -> [Text]
+ Miso.String: instance Miso.String.FromMisoString Data.ByteString.Builder.Internal.Builder
+ Miso.String: instance Miso.String.FromMisoString Data.Text.Internal.Text
+ Miso.String: instance Miso.String.ToMisoString Data.ByteString.Builder.Internal.Builder
+ Miso.String: instance Miso.String.ToMisoString Data.Text.Internal.Text
+ Miso.String: instance Miso.String.ToMisoString GHC.Exception.Type.SomeException
+ Miso.String: instance Miso.String.ToMisoString GHC.IO.Exception.IOException
+ Miso.String: instance Miso.String.ToMisoString GHC.Types.Char
+ Miso.String: instance Miso.String.ToMisoString a => Miso.String.ToMisoString (GHC.Maybe.Maybe a)
+ Miso.String: intercalate :: Text -> [Text] -> Text
+ Miso.String: intersperse :: Char -> Text -> Text
+ Miso.String: isAscii :: Text -> Bool
+ Miso.String: isInfixOf :: Text -> Text -> Bool
+ Miso.String: isPrefixOf :: Text -> Text -> Bool
+ Miso.String: isSuffixOf :: Text -> Text -> Bool
+ Miso.String: justifyLeft :: Int -> Char -> Text -> Text
+ Miso.String: justifyRight :: Int -> Char -> Text -> Text
+ Miso.String: last :: HasCallStack => Text -> Char
+ Miso.String: length :: Text -> Int
+ Miso.String: lines :: Text -> [Text]
+ Miso.String: map :: (Char -> Char) -> Text -> Text
+ Miso.String: mapAccumL :: (a -> Char -> (a, Char)) -> a -> Text -> (a, Text)
+ Miso.String: mapAccumR :: (a -> Char -> (a, Char)) -> a -> Text -> (a, Text)
+ Miso.String: maximum :: HasCallStack => Text -> Char
+ Miso.String: measureOff :: Int -> Text -> Int
+ Miso.String: minimum :: HasCallStack => Text -> Char
+ Miso.String: null :: Text -> Bool
+ Miso.String: pack :: String -> Text
+ Miso.String: partition :: (Char -> Bool) -> Text -> (Text, Text)
+ Miso.String: replace :: HasCallStack => Text -> Text -> Text -> Text
+ Miso.String: replicate :: Int -> Text -> Text
+ Miso.String: reverse :: Text -> Text
+ Miso.String: scanl :: (Char -> Char -> Char) -> Char -> Text -> Text
+ Miso.String: scanl1 :: (Char -> Char -> Char) -> Text -> Text
+ Miso.String: scanr :: (Char -> Char -> Char) -> Char -> Text -> Text
+ Miso.String: scanr1 :: (Char -> Char -> Char) -> Text -> Text
+ Miso.String: singleton :: Char -> Text
+ Miso.String: snoc :: Text -> Char -> Text
+ Miso.String: span :: (Char -> Bool) -> Text -> (Text, Text)
+ Miso.String: spanEndM :: Monad m => (Char -> m Bool) -> Text -> m (Text, Text)
+ Miso.String: spanM :: Monad m => (Char -> m Bool) -> Text -> m (Text, Text)
+ Miso.String: split :: (Char -> Bool) -> Text -> [Text]
+ Miso.String: splitAt :: Int -> Text -> (Text, Text)
+ Miso.String: splitOn :: HasCallStack => Text -> Text -> [Text]
+ Miso.String: strip :: Text -> Text
+ Miso.String: stripEnd :: Text -> Text
+ Miso.String: stripPrefix :: Text -> Text -> Maybe Text
+ Miso.String: stripStart :: Text -> Text
+ Miso.String: stripSuffix :: Text -> Text -> Maybe Text
+ Miso.String: tail :: HasCallStack => Text -> Text
+ Miso.String: tails :: Text -> [Text]
+ Miso.String: take :: Int -> Text -> Text
+ Miso.String: takeEnd :: Int -> Text -> Text
+ Miso.String: takeWhile :: (Char -> Bool) -> Text -> Text
+ Miso.String: takeWhileEnd :: (Char -> Bool) -> Text -> Text
+ Miso.String: toCaseFold :: Text -> Text
+ Miso.String: toLower :: Text -> Text
+ Miso.String: toTitle :: Text -> Text
+ Miso.String: toUpper :: Text -> Text
+ Miso.String: transpose :: [Text] -> [Text]
+ Miso.String: type StrictText = Text
+ Miso.String: uncons :: Text -> Maybe (Char, Text)
+ Miso.String: unfoldr :: (a -> Maybe (Char, a)) -> a -> Text
+ Miso.String: unfoldrN :: Int -> (a -> Maybe (Char, a)) -> a -> Text
+ Miso.String: unlines :: [Text] -> Text
+ Miso.String: unpack :: Text -> String
+ Miso.String: unpackCString# :: Addr# -> Text
+ Miso.String: unpackCStringAscii# :: Addr# -> Text
+ Miso.String: unsnoc :: Text -> Maybe (Text, Char)
+ Miso.String: unwords :: [Text] -> Text
+ Miso.String: words :: Text -> [Text]
+ Miso.String: zip :: Text -> Text -> [(Char, Char)]
+ Miso.String: zipWith :: (Char -> Char -> Char) -> Text -> Text -> Text
+ Miso.Subscription.History: [uriQueryString] :: URI -> Map MisoString (Maybe MisoString)
+ Miso.Subscription.History: getURI :: IO URI
+ Miso.Subscription.History: pushRoute :: Router route => route -> IO ()
+ Miso.Subscription.History: routerSub :: Router route => (Either RoutingError route -> action) -> Sub action
+ Miso.Subscription.OnLine: onLineSub :: (Bool -> action) -> Sub action
+ Miso.Subscription.Util: createSub :: IO a -> (a -> IO b) -> Sub action
+ Miso.Subscription.Window: type Coord = (Double, Double)
+ Miso.Subscription.Window: windowPointerMoveSub :: (PointerEvent -> action) -> Sub action
+ Miso.Svg.Element: feDropShadow_ :: [Attribute action] -> View model action
+ Miso.Svg.Element: feMorphology_ :: [Attribute action] -> View model action
+ Miso.Svg.Property: accumulate_ :: MisoString -> Attribute action
+ Miso.Svg.Property: additive_ :: MisoString -> Attribute action
+ Miso.Svg.Property: alignmentBaseline_ :: MisoString -> Attribute action
+ Miso.Svg.Property: amplitude_ :: MisoString -> Attribute action
+ Miso.Svg.Property: attributeName_ :: MisoString -> Attribute action
+ Miso.Svg.Property: azimuth_ :: MisoString -> Attribute action
+ Miso.Svg.Property: baseFrequency_ :: MisoString -> Attribute action
+ Miso.Svg.Property: baselineShift_ :: MisoString -> Attribute action
+ Miso.Svg.Property: begin_ :: MisoString -> Attribute action
+ Miso.Svg.Property: bias_ :: MisoString -> Attribute action
+ Miso.Svg.Property: by_ :: MisoString -> Attribute action
+ Miso.Svg.Property: calcMode_ :: MisoString -> Attribute action
+ Miso.Svg.Property: clipPathUnits_ :: MisoString -> Attribute action
+ Miso.Svg.Property: clipPath_ :: MisoString -> Attribute action
+ Miso.Svg.Property: clipRule_ :: MisoString -> Attribute action
+ Miso.Svg.Property: colorInterpolationFilters_ :: MisoString -> Attribute action
+ Miso.Svg.Property: colorInterpolation_ :: MisoString -> Attribute action
+ Miso.Svg.Property: color_ :: MisoString -> Attribute action
+ Miso.Svg.Property: crossorigin_ :: MisoString -> Attribute action
+ Miso.Svg.Property: cursor_ :: MisoString -> Attribute action
+ Miso.Svg.Property: cx_ :: MisoString -> Attribute action
+ Miso.Svg.Property: cy_ :: MisoString -> Attribute action
+ Miso.Svg.Property: d_ :: MisoString -> Attribute action
+ Miso.Svg.Property: decoding_ :: MisoString -> Attribute action
+ Miso.Svg.Property: diffuseConstant_ :: MisoString -> Attribute action
+ Miso.Svg.Property: direction_ :: MisoString -> Attribute action
+ Miso.Svg.Property: display_ :: MisoString -> Attribute action
+ Miso.Svg.Property: divisor_ :: MisoString -> Attribute action
+ Miso.Svg.Property: dominantBaseline_ :: MisoString -> Attribute action
+ Miso.Svg.Property: dur_ :: MisoString -> Attribute action
+ Miso.Svg.Property: dx_ :: MisoString -> Attribute action
+ Miso.Svg.Property: dy_ :: MisoString -> Attribute action
+ Miso.Svg.Property: edgeMode_ :: MisoString -> Attribute action
+ Miso.Svg.Property: elevation_ :: MisoString -> Attribute action
+ Miso.Svg.Property: end_ :: MisoString -> Attribute action
+ Miso.Svg.Property: exponent_ :: MisoString -> Attribute action
+ Miso.Svg.Property: fillOpacity_ :: MisoString -> Attribute action
+ Miso.Svg.Property: fillRule_ :: MisoString -> Attribute action
+ Miso.Svg.Property: fill_ :: MisoString -> Attribute action
+ Miso.Svg.Property: filterUnits_ :: MisoString -> Attribute action
+ Miso.Svg.Property: filter_ :: MisoString -> Attribute action
+ Miso.Svg.Property: floodColor_ :: MisoString -> Attribute action
+ Miso.Svg.Property: floodOpacity_ :: MisoString -> Attribute action
+ Miso.Svg.Property: fontFamily_ :: MisoString -> Attribute action
+ Miso.Svg.Property: fontSizeAdjust_ :: MisoString -> Attribute action
+ Miso.Svg.Property: fontSize_ :: MisoString -> Attribute action
+ Miso.Svg.Property: fontStyle_ :: MisoString -> Attribute action
+ Miso.Svg.Property: fontVariant_ :: MisoString -> Attribute action
+ Miso.Svg.Property: fontWeight_ :: MisoString -> Attribute action
+ Miso.Svg.Property: fr_ :: MisoString -> Attribute action
+ Miso.Svg.Property: from_ :: MisoString -> Attribute action
+ Miso.Svg.Property: fx_ :: MisoString -> Attribute action
+ Miso.Svg.Property: fy_ :: MisoString -> Attribute action
+ Miso.Svg.Property: gradientTransform_ :: MisoString -> Attribute action
+ Miso.Svg.Property: gradientUnits_ :: MisoString -> Attribute action
+ Miso.Svg.Property: imageRendering_ :: MisoString -> Attribute action
+ Miso.Svg.Property: in2_ :: MisoString -> Attribute action
+ Miso.Svg.Property: in_' :: MisoString -> Attribute action
+ Miso.Svg.Property: intercept_ :: MisoString -> Attribute action
+ Miso.Svg.Property: k1_ :: MisoString -> Attribute action
+ Miso.Svg.Property: k2_ :: MisoString -> Attribute action
+ Miso.Svg.Property: k3_ :: MisoString -> Attribute action
+ Miso.Svg.Property: k4_ :: MisoString -> Attribute action
+ Miso.Svg.Property: kernelMatrix_ :: MisoString -> Attribute action
+ Miso.Svg.Property: keyPoints_ :: MisoString -> Attribute action
+ Miso.Svg.Property: keySplines_ :: MisoString -> Attribute action
+ Miso.Svg.Property: keyTimes_ :: MisoString -> Attribute action
+ Miso.Svg.Property: lengthAdjust_ :: MisoString -> Attribute action
+ Miso.Svg.Property: letterSpacing_ :: MisoString -> Attribute action
+ Miso.Svg.Property: lightingColor_ :: MisoString -> Attribute action
+ Miso.Svg.Property: limitingConeAngle_ :: MisoString -> Attribute action
+ Miso.Svg.Property: markerEnd_ :: MisoString -> Attribute action
+ Miso.Svg.Property: markerHeight_ :: MisoString -> Attribute action
+ Miso.Svg.Property: markerMid_ :: MisoString -> Attribute action
+ Miso.Svg.Property: markerStart_ :: MisoString -> Attribute action
+ Miso.Svg.Property: markerUnits_ :: MisoString -> Attribute action
+ Miso.Svg.Property: markerWidth_ :: MisoString -> Attribute action
+ Miso.Svg.Property: maskContentUnits_ :: MisoString -> Attribute action
+ Miso.Svg.Property: maskUnits_ :: MisoString -> Attribute action
+ Miso.Svg.Property: mask_ :: MisoString -> Attribute action
+ Miso.Svg.Property: max_ :: MisoString -> Attribute action
+ Miso.Svg.Property: media_ :: MisoString -> Attribute action
+ Miso.Svg.Property: method_ :: MisoString -> Attribute action
+ Miso.Svg.Property: min_ :: MisoString -> Attribute action
+ Miso.Svg.Property: mode_ :: MisoString -> Attribute action
+ Miso.Svg.Property: numOctaves_ :: MisoString -> Attribute action
+ Miso.Svg.Property: opacity_ :: MisoString -> Attribute action
+ Miso.Svg.Property: operator_ :: MisoString -> Attribute action
+ Miso.Svg.Property: order_ :: MisoString -> Attribute action
+ Miso.Svg.Property: orient_ :: MisoString -> Attribute action
+ Miso.Svg.Property: origin_ :: MisoString -> Attribute action
+ Miso.Svg.Property: overflow_ :: MisoString -> Attribute action
+ Miso.Svg.Property: paintOrder_ :: MisoString -> Attribute action
+ Miso.Svg.Property: pathLength_ :: MisoString -> Attribute action
+ Miso.Svg.Property: path_ :: MisoString -> Attribute action
+ Miso.Svg.Property: patternContentUnits_ :: MisoString -> Attribute action
+ Miso.Svg.Property: patternTransform_ :: MisoString -> Attribute action
+ Miso.Svg.Property: patternUnits_ :: MisoString -> Attribute action
+ Miso.Svg.Property: pointerEvents_ :: MisoString -> Attribute action
+ Miso.Svg.Property: pointsAtX_ :: MisoString -> Attribute action
+ Miso.Svg.Property: pointsAtY_ :: MisoString -> Attribute action
+ Miso.Svg.Property: pointsAtZ_ :: MisoString -> Attribute action
+ Miso.Svg.Property: points_ :: MisoString -> Attribute action
+ Miso.Svg.Property: preserveAlpha_ :: MisoString -> Attribute action
+ Miso.Svg.Property: preserveAspectRatio_ :: MisoString -> Attribute action
+ Miso.Svg.Property: primitiveUnits_ :: MisoString -> Attribute action
+ Miso.Svg.Property: r_ :: MisoString -> Attribute action
+ Miso.Svg.Property: radius_ :: MisoString -> Attribute action
+ Miso.Svg.Property: refX_ :: MisoString -> Attribute action
+ Miso.Svg.Property: refY_ :: MisoString -> Attribute action
+ Miso.Svg.Property: repeatCount_ :: MisoString -> Attribute action
+ Miso.Svg.Property: repeatDur_ :: MisoString -> Attribute action
+ Miso.Svg.Property: restart_ :: MisoString -> Attribute action
+ Miso.Svg.Property: result_ :: MisoString -> Attribute action
+ Miso.Svg.Property: rotate_ :: MisoString -> Attribute action
+ Miso.Svg.Property: rx_ :: MisoString -> Attribute action
+ Miso.Svg.Property: ry_ :: MisoString -> Attribute action
+ Miso.Svg.Property: scale_ :: MisoString -> Attribute action
+ Miso.Svg.Property: seed_ :: MisoString -> Attribute action
+ Miso.Svg.Property: shapeRendering_ :: MisoString -> Attribute action
+ Miso.Svg.Property: side_ :: MisoString -> Attribute action
+ Miso.Svg.Property: slope_ :: MisoString -> Attribute action
+ Miso.Svg.Property: spacing_ :: MisoString -> Attribute action
+ Miso.Svg.Property: specularConstant_ :: MisoString -> Attribute action
+ Miso.Svg.Property: specularExponent_ :: MisoString -> Attribute action
+ Miso.Svg.Property: spreadMethod_ :: MisoString -> Attribute action
+ Miso.Svg.Property: startOffset_ :: MisoString -> Attribute action
+ Miso.Svg.Property: stdDeviation_ :: MisoString -> Attribute action
+ Miso.Svg.Property: stitchTiles_ :: MisoString -> Attribute action
+ Miso.Svg.Property: stopColor_ :: MisoString -> Attribute action
+ Miso.Svg.Property: stopOpacity_ :: MisoString -> Attribute action
+ Miso.Svg.Property: strokeDasharray_ :: MisoString -> Attribute action
+ Miso.Svg.Property: strokeDashoffset_ :: MisoString -> Attribute action
+ Miso.Svg.Property: strokeLinecap_ :: MisoString -> Attribute action
+ Miso.Svg.Property: strokeLinejoin_ :: MisoString -> Attribute action
+ Miso.Svg.Property: strokeMiterlimit_ :: MisoString -> Attribute action
+ Miso.Svg.Property: strokeOpacity_ :: MisoString -> Attribute action
+ Miso.Svg.Property: strokeWidth_ :: MisoString -> Attribute action
+ Miso.Svg.Property: stroke_ :: MisoString -> Attribute action
+ Miso.Svg.Property: surfaceScale_ :: MisoString -> Attribute action
+ Miso.Svg.Property: systemLanguage_ :: MisoString -> Attribute action
+ Miso.Svg.Property: tableValues_ :: MisoString -> Attribute action
+ Miso.Svg.Property: targetX_ :: MisoString -> Attribute action
+ Miso.Svg.Property: targetY_ :: MisoString -> Attribute action
+ Miso.Svg.Property: target_ :: MisoString -> Attribute action
+ Miso.Svg.Property: textAnchor_ :: MisoString -> Attribute action
+ Miso.Svg.Property: textDecoration_ :: MisoString -> Attribute action
+ Miso.Svg.Property: textLength_ :: MisoString -> Attribute action
+ Miso.Svg.Property: textRendering_ :: MisoString -> Attribute action
+ Miso.Svg.Property: to_ :: MisoString -> Attribute action
+ Miso.Svg.Property: transformOrigin_ :: MisoString -> Attribute action
+ Miso.Svg.Property: transform_ :: MisoString -> Attribute action
+ Miso.Svg.Property: type_' :: MisoString -> Attribute action
+ Miso.Svg.Property: unicodeBidi_ :: MisoString -> Attribute action
+ Miso.Svg.Property: values_ :: MisoString -> Attribute action
+ Miso.Svg.Property: vectorEffect_ :: MisoString -> Attribute action
+ Miso.Svg.Property: viewBox_ :: MisoString -> Attribute action
+ Miso.Svg.Property: visibility_ :: MisoString -> Attribute action
+ Miso.Svg.Property: wordSpacing_ :: MisoString -> Attribute action
+ Miso.Svg.Property: writingMode_ :: MisoString -> Attribute action
+ Miso.Svg.Property: x1_ :: MisoString -> Attribute action
+ Miso.Svg.Property: x2_ :: MisoString -> Attribute action
+ Miso.Svg.Property: xChannelSelector_ :: MisoString -> Attribute action
+ Miso.Svg.Property: x_ :: MisoString -> Attribute action
+ Miso.Svg.Property: y1_ :: MisoString -> Attribute action
+ Miso.Svg.Property: y2_ :: MisoString -> Attribute action
+ Miso.Svg.Property: yChannelSelector_ :: MisoString -> Attribute action
+ Miso.Svg.Property: y_ :: MisoString -> Attribute action
+ Miso.Svg.Property: z_ :: MisoString -> Attribute action
+ Miso.Types: (+>) :: Eq child => MisoString -> Component model child action -> View model a
+ Miso.Types: (--->) :: Lens' parent field -> Lens' child field -> Binding parent child
+ Miso.Types: (-->) :: Lens parent a -> Lens model a -> Binding parent model
+ Miso.Types: (<--) :: Lens parent a -> Lens model a -> Binding parent model
+ Miso.Types: (<---) :: Lens' parent field -> Lens' child field -> Binding parent child
+ Miso.Types: (<--->) :: Lens' parent field -> Lens' child field -> Binding parent child
+ Miso.Types: (<-->) :: Lens parent field -> Lens child field -> Binding parent child
+ Miso.Types: BUBBLE :: Phase
+ Miso.Types: Bidirectional :: (parent -> field) -> (field -> parent -> parent) -> (child -> field) -> (field -> child -> child) -> Binding parent child
+ Miso.Types: CAPTURE :: Phase
+ Miso.Types: ChildToParent :: (field -> parent -> parent) -> (child -> field) -> Binding parent child
+ Miso.Types: ClassList :: [MisoString] -> Attribute action
+ Miso.Types: Component :: model -> Maybe (IO model) -> (action -> Effect parent model action) -> (model -> View model action) -> [Sub action] -> [CSS] -> [JS] -> Maybe MountPoint -> LogLevel -> (Value -> Maybe action) -> [Binding parent model] -> Bool -> Maybe action -> Maybe action -> Component parent model action
+ Miso.Types: DebugAll :: LogLevel
+ Miso.Types: DebugEvents :: LogLevel
+ Miso.Types: DebugHydrate :: LogLevel
+ Miso.Types: HTML :: Namespace
+ Miso.Types: Href :: MisoString -> CacheBust -> CSS
+ Miso.Types: ImportMap :: [(MisoString, MisoString)] -> JS
+ Miso.Types: Key :: MisoString -> Key
+ Miso.Types: MATHML :: Namespace
+ Miso.Types: Module :: MisoString -> JS
+ Miso.Types: On :: (Sink action -> VTree -> LogLevel -> Events -> IO ()) -> Attribute action
+ Miso.Types: ParentToChild :: (parent -> field) -> (field -> child -> child) -> Binding parent child
+ Miso.Types: Property :: MisoString -> Value -> Attribute action
+ Miso.Types: SVG :: Namespace
+ Miso.Types: Script :: MisoString -> JS
+ Miso.Types: Sheet :: StyleSheet -> CSS
+ Miso.Types: SomeComponent :: Component parent model action -> SomeComponent parent
+ Miso.Types: Src :: MisoString -> CacheBust -> JS
+ Miso.Types: Style :: MisoString -> CSS
+ Miso.Types: Styles :: Map MisoString MisoString -> Attribute action
+ Miso.Types: URI :: MisoString -> MisoString -> Map MisoString (Maybe MisoString) -> URI
+ Miso.Types: VComp :: Maybe Key -> SomeComponent model -> View model action
+ Miso.Types: VCompType :: VTreeType
+ Miso.Types: VNode :: Namespace -> Tag -> [Attribute action] -> [View model action] -> View model action
+ Miso.Types: VNodeType :: VTreeType
+ Miso.Types: VText :: Maybe Key -> MisoString -> View model action
+ Miso.Types: VTextType :: VTreeType
+ Miso.Types: VTree :: Object -> VTree
+ Miso.Types: [bindings] :: Component parent model action -> [Binding parent model]
+ Miso.Types: [eventPropagation] :: Component parent model action -> Bool
+ Miso.Types: [getTree] :: VTree -> Object
+ Miso.Types: [hydrateModel] :: Component parent model action -> Maybe (IO model)
+ Miso.Types: [mailbox] :: Component parent model action -> Value -> Maybe action
+ Miso.Types: [mount] :: Component parent model action -> Maybe action
+ Miso.Types: [scripts] :: Component parent model action -> [JS]
+ Miso.Types: [styles] :: Component parent model action -> [CSS]
+ Miso.Types: [unmount] :: Component parent model action -> Maybe action
+ Miso.Types: [uriFragment] :: URI -> MisoString
+ Miso.Types: [uriPath] :: URI -> MisoString
+ Miso.Types: [uriQueryString] :: URI -> Map MisoString (Maybe MisoString)
+ Miso.Types: class ToKey key
+ Miso.Types: component :: model -> (action -> Effect parent model action) -> (model -> View model action) -> Component parent model action
+ Miso.Types: data Attribute action
+ Miso.Types: data Binding parent child
+ Miso.Types: data CSS
+ Miso.Types: data Component parent model action
+ Miso.Types: data JS
+ Miso.Types: data Namespace
+ Miso.Types: data Phase
+ Miso.Types: data ROOT
+ Miso.Types: data SomeComponent parent
+ Miso.Types: data URI
+ Miso.Types: data VTreeType
+ Miso.Types: data View model action
+ Miso.Types: emptyURI :: URI
+ Miso.Types: fromMisoString :: FromMisoString a => MisoString -> a
+ Miso.Types: getMountPoint :: Maybe MisoString -> MisoString
+ Miso.Types: htmlEncode :: MisoString -> MisoString
+ Miso.Types: infix 0 <--->
+ Miso.Types: infixl 0 <---
+ Miso.Types: infixr 0 +>
+ Miso.Types: instance Data.String.IsString (Miso.Types.View model action)
+ Miso.Types: instance Data.String.IsString Miso.Types.Key
+ Miso.Types: instance GHC.Base.Functor (Miso.Types.View model)
+ Miso.Types: instance GHC.Base.Functor Miso.Types.Attribute
+ Miso.Types: instance GHC.Classes.Eq (Miso.Types.Attribute action)
+ Miso.Types: instance GHC.Classes.Eq Miso.Types.CSS
+ Miso.Types: instance GHC.Classes.Eq Miso.Types.JS
+ Miso.Types: instance GHC.Classes.Eq Miso.Types.Key
+ Miso.Types: instance GHC.Classes.Eq Miso.Types.Namespace
+ Miso.Types: instance GHC.Classes.Eq Miso.Types.ROOT
+ Miso.Types: instance GHC.Classes.Eq Miso.Types.URI
+ Miso.Types: instance GHC.Classes.Eq Miso.Types.VTreeType
+ Miso.Types: instance GHC.Generics.Generic Miso.Types.URI
+ Miso.Types: instance GHC.Show.Show (Miso.Types.Attribute action)
+ Miso.Types: instance GHC.Show.Show Miso.Types.CSS
+ Miso.Types: instance GHC.Show.Show Miso.Types.JS
+ Miso.Types: instance GHC.Show.Show Miso.Types.Key
+ Miso.Types: instance GHC.Show.Show Miso.Types.Namespace
+ Miso.Types: instance GHC.Show.Show Miso.Types.URI
+ Miso.Types: instance GHC.Show.Show Miso.Types.VTreeType
+ Miso.Types: instance Miso.DSL.ToJSVal Miso.Types.Key
+ Miso.Types: instance Miso.DSL.ToJSVal Miso.Types.Namespace
+ Miso.Types: instance Miso.DSL.ToJSVal Miso.Types.URI
+ Miso.Types: instance Miso.DSL.ToJSVal Miso.Types.VTree
+ Miso.Types: instance Miso.DSL.ToJSVal Miso.Types.VTreeType
+ Miso.Types: instance Miso.DSL.ToObject Miso.Types.URI
+ Miso.Types: instance Miso.DSL.ToObject Miso.Types.VTree
+ Miso.Types: instance Miso.JSON.ToJSON Miso.Types.Key
+ Miso.Types: instance Miso.String.ToMisoString Miso.Types.Key
+ Miso.Types: instance Miso.String.ToMisoString Miso.Types.URI
+ Miso.Types: instance Miso.Types.ToKey Data.Text.Internal.Text
+ Miso.Types: instance Miso.Types.ToKey GHC.Base.String
+ Miso.Types: instance Miso.Types.ToKey GHC.Types.Double
+ Miso.Types: instance Miso.Types.ToKey GHC.Types.Float
+ Miso.Types: instance Miso.Types.ToKey GHC.Types.Int
+ Miso.Types: instance Miso.Types.ToKey GHC.Types.Word
+ Miso.Types: instance Miso.Types.ToKey Miso.Types.Key
+ Miso.Types: mount_ :: Eq child => Component model child a -> View model action
+ Miso.Types: ms :: ToMisoString str => str -> MisoString
+ Miso.Types: newtype Key
+ Miso.Types: newtype VTree
+ Miso.Types: node :: Namespace -> MisoString -> [Attribute action] -> [View model action] -> View model action
+ Miso.Types: optionalAttrs :: ([Attribute action] -> [View model action] -> View model action) -> [Attribute action] -> Bool -> [Attribute action] -> [View model action] -> View model action
+ Miso.Types: optionalChildren :: ([Attribute action] -> [View model action] -> View model action) -> [Attribute action] -> [View model action] -> Bool -> [View model action] -> View model action
+ Miso.Types: prettyQueryString :: URI -> MisoString
+ Miso.Types: prettyURI :: URI -> MisoString
+ Miso.Types: text :: MisoString -> View model action
+ Miso.Types: textKey :: ToKey key => key -> MisoString -> View model action
+ Miso.Types: textKey_ :: ToKey key => key -> [MisoString] -> View model action
+ Miso.Types: textRaw :: MisoString -> View model action
+ Miso.Types: text_ :: [MisoString] -> View model action
+ Miso.Types: toKey :: ToKey key => key -> Key
+ Miso.Types: toMisoString :: ToMisoString str => str -> MisoString
+ Miso.Types: type App model action = Component ROOT model action
+ Miso.Types: type CacheBust = Bool
+ Miso.Types: type ComponentId = Int
+ Miso.Types: type DOMRef = JSVal
+ Miso.Types: type Events = Map MisoString Phase
+ Miso.Types: type MisoString = Text
+ Miso.Types: type MountPoint = MisoString
+ Miso.Types: type Tag = MisoString
+ Miso.Types: vcomp :: model -> (action -> Effect parent model action) -> (model -> View model action) -> Component parent model action
+ Miso.Types: vnode :: Namespace -> MisoString -> [Attribute action] -> [View model action] -> View model action
+ Miso.Types: vtext :: MisoString -> View model action
+ Miso.Util: between :: Applicative f => f a -> f b -> f c -> f (b, c)
+ Miso.Util: compose :: Category cat => cat a b -> cat b c -> cat a c
+ Miso.Util: enclosed :: Applicative f => f a -> f b -> f c -> f c
+ Miso.Util: exists :: Alternative f => f a -> f Bool
+ Miso.Util: oneOf :: Alternative f => [f a] -> f a
+ Miso.Util: optionalDefault :: Alternative f => b -> f b -> f b
+ Miso.Util: sepBy :: Alternative m => m sep -> m a -> m [a]
+ Miso.Util: sepBy1 :: Alternative m => m sep -> m a -> m [a]
+ Miso.Util.Lexer: Lexer :: (Stream -> Either LexerError (token, Stream)) -> Lexer token
+ Miso.Util.Lexer: LexerError :: MisoString -> Location -> LexerError
+ Miso.Util.Lexer: Located :: token -> Location -> Located token
+ Miso.Util.Lexer: Location :: Int -> (Int, Int) -> Location
+ Miso.Util.Lexer: Stream :: MisoString -> Location -> Stream
+ Miso.Util.Lexer: UnexpectedEOF :: Location -> LexerError
+ Miso.Util.Lexer: [column] :: Location -> (Int, Int)
+ Miso.Util.Lexer: [currentLocation] :: Stream -> Location
+ Miso.Util.Lexer: [line] :: Location -> Int
+ Miso.Util.Lexer: [location] :: Located token -> Location
+ Miso.Util.Lexer: [runLexer] :: Lexer token -> Stream -> Either LexerError (token, Stream)
+ Miso.Util.Lexer: [stream] :: Stream -> MisoString
+ Miso.Util.Lexer: [token] :: Located token -> token
+ Miso.Util.Lexer: char :: Char -> Lexer Char
+ Miso.Util.Lexer: data LexerError
+ Miso.Util.Lexer: data Located token
+ Miso.Util.Lexer: data Location
+ Miso.Util.Lexer: data Stream
+ Miso.Util.Lexer: getInput :: Lexer Stream
+ Miso.Util.Lexer: getLocation :: Lexer Location
+ Miso.Util.Lexer: getStartColumn :: Location -> Int
+ Miso.Util.Lexer: initialLocation :: Location
+ Miso.Util.Lexer: instance GHC.Base.Alternative Miso.Util.Lexer.Lexer
+ Miso.Util.Lexer: instance GHC.Base.Applicative Miso.Util.Lexer.Lexer
+ Miso.Util.Lexer: instance GHC.Base.Functor Miso.Util.Lexer.Lexer
+ Miso.Util.Lexer: instance GHC.Base.Monad Miso.Util.Lexer.Lexer
+ Miso.Util.Lexer: instance GHC.Base.MonadPlus Miso.Util.Lexer.Lexer
+ Miso.Util.Lexer: instance GHC.Classes.Eq Miso.Util.Lexer.LexerError
+ Miso.Util.Lexer: instance GHC.Classes.Eq Miso.Util.Lexer.Location
+ Miso.Util.Lexer: instance GHC.Classes.Eq Miso.Util.Lexer.Stream
+ Miso.Util.Lexer: instance GHC.Classes.Eq token => GHC.Classes.Eq (Miso.Util.Lexer.Located token)
+ Miso.Util.Lexer: instance GHC.Show.Show Miso.Util.Lexer.LexerError
+ Miso.Util.Lexer: instance GHC.Show.Show Miso.Util.Lexer.Location
+ Miso.Util.Lexer: instance GHC.Show.Show token => GHC.Show.Show (Miso.Util.Lexer.Located token)
+ Miso.Util.Lexer: mkStream :: MisoString -> Stream
+ Miso.Util.Lexer: modifyInput :: (Stream -> Stream) -> Lexer ()
+ Miso.Util.Lexer: newtype Lexer token
+ Miso.Util.Lexer: oops :: Lexer token
+ Miso.Util.Lexer: peek :: Lexer (Maybe Char)
+ Miso.Util.Lexer: putInput :: Stream -> Lexer ()
+ Miso.Util.Lexer: satisfy :: (Char -> Bool) -> Lexer Char
+ Miso.Util.Lexer: setLocation :: Location -> Lexer ()
+ Miso.Util.Lexer: streamError :: Stream -> LexerError
+ Miso.Util.Lexer: string :: MisoString -> Lexer MisoString
+ Miso.Util.Lexer: string' :: String -> Lexer String
+ Miso.Util.Lexer: withLocation :: ToMisoString token => Lexer token -> Lexer (Located token)
+ Miso.Util.Lexer: zeroLocation :: Location
+ Miso.Util.Parser: Ambiguous :: [(a, [token])] -> ParseError a token
+ Miso.Util.Parser: EmptyStream :: ParseError a token
+ Miso.Util.Parser: LexicalError :: LexerError -> ParseError a token
+ Miso.Util.Parser: NoParses :: token -> ParseError a token
+ Miso.Util.Parser: Parser :: (r -> token -> m (a, token)) -> ParserT r token (m :: Type -> Type) a
+ Miso.Util.Parser: UnexpectedParse :: [token] -> ParseError a token
+ Miso.Util.Parser: [runParserT] :: ParserT r token (m :: Type -> Type) a -> r -> token -> m (a, token)
+ Miso.Util.Parser: allTokens :: ParserT r a [] a
+ Miso.Util.Parser: anyToken :: ParserT r [a] [] a
+ Miso.Util.Parser: askParser :: ParserT r token [] r
+ Miso.Util.Parser: data ParseError a token
+ Miso.Util.Parser: endOfInput :: Parser a ()
+ Miso.Util.Parser: errorOut :: errorToken -> ParserT r errorToken [] ()
+ Miso.Util.Parser: instance (GHC.Classes.Eq a, GHC.Classes.Eq token) => GHC.Classes.Eq (Miso.Util.Parser.ParseError a token)
+ Miso.Util.Parser: instance (GHC.Show.Show a, GHC.Show.Show token) => GHC.Show.Show (Miso.Util.Parser.ParseError a token)
+ Miso.Util.Parser: instance Control.Monad.Fail.MonadFail (Miso.Util.Parser.ParserT r token [])
+ Miso.Util.Parser: instance GHC.Base.Alternative (Miso.Util.Parser.ParserT r token [])
+ Miso.Util.Parser: instance GHC.Base.Applicative (Miso.Util.Parser.ParserT r token [])
+ Miso.Util.Parser: instance GHC.Base.Functor (Miso.Util.Parser.ParserT r token [])
+ Miso.Util.Parser: instance GHC.Base.Monad (Miso.Util.Parser.ParserT r token [])
+ Miso.Util.Parser: instance GHC.Base.MonadPlus (Miso.Util.Parser.ParserT r token [])
+ Miso.Util.Parser: modifyTokens :: (t -> t) -> ParserT r t [] ()
+ Miso.Util.Parser: newtype ParserT r token (m :: Type -> Type) a
+ Miso.Util.Parser: parse :: Parser token a -> [token] -> Either (ParseError a token) a
+ Miso.Util.Parser: peek :: Parser a a
+ Miso.Util.Parser: satisfy :: (a -> Bool) -> ParserT r [a] [] a
+ Miso.Util.Parser: token_ :: Eq token => token -> Parser token token
+ Miso.Util.Parser: type Parser token a = ParserT () [token] [] a
+ Miso.WebSocket: ArrayBuffer :: JSVal -> ArrayBuffer
+ Miso.WebSocket: BLOB :: Blob -> Payload value
+ Miso.WebSocket: BUFFER :: ArrayBuffer -> Payload value
+ Miso.WebSocket: Blob :: JSVal -> Blob
+ Miso.WebSocket: Closed :: CloseCode -> Bool -> MisoString -> Closed
+ Miso.WebSocket: JSON :: value -> Payload value
+ Miso.WebSocket: TEXT :: MisoString -> Payload value
+ Miso.WebSocket: WebSocket :: Int -> WebSocket
+ Miso.WebSocket: [closedCode] :: Closed -> CloseCode
+ Miso.WebSocket: [reason] :: Closed -> MisoString
+ Miso.WebSocket: [wasClean] :: Closed -> Bool
+ Miso.WebSocket: close :: WebSocket -> Effect parent model action
+ Miso.WebSocket: connect :: FromJSON json => URL -> (WebSocket -> action) -> (Closed -> action) -> (Payload json -> action) -> (MisoString -> action) -> Effect parent model action
+ Miso.WebSocket: connectArrayBuffer :: URL -> (WebSocket -> action) -> (Closed -> action) -> (ArrayBuffer -> action) -> (MisoString -> action) -> Effect parent model action
+ Miso.WebSocket: connectBLOB :: URL -> (WebSocket -> action) -> (Closed -> action) -> (Blob -> action) -> (MisoString -> action) -> Effect parent model action
+ Miso.WebSocket: connectJSON :: FromJSON json => URL -> (WebSocket -> action) -> (Closed -> action) -> (json -> action) -> (MisoString -> action) -> Effect parent model action
+ Miso.WebSocket: connectText :: URL -> (WebSocket -> action) -> (Closed -> action) -> (MisoString -> action) -> (MisoString -> action) -> Effect parent model action
+ Miso.WebSocket: data Closed
+ Miso.WebSocket: data Payload value
+ Miso.WebSocket: emptyWebSocket :: WebSocket
+ Miso.WebSocket: newtype ArrayBuffer
+ Miso.WebSocket: newtype Blob
+ Miso.WebSocket: newtype WebSocket
+ Miso.WebSocket: sendArrayBuffer :: WebSocket -> ArrayBuffer -> Effect parent model action
+ Miso.WebSocket: sendBLOB :: WebSocket -> Blob -> Effect parent model action
+ Miso.WebSocket: sendJSON :: ToJSON json => WebSocket -> json -> Effect parent model action
+ Miso.WebSocket: sendText :: WebSocket -> MisoString -> Effect parent model action
+ Miso.WebSocket: socketState :: WebSocket -> (SocketState -> action) -> Effect parent model action
+ Miso.WebSocket: type URL = MisoString
- Miso: miso :: Eq model => (URI -> App model action) -> JSM ()
+ Miso: miso :: Eq model => Events -> (URI -> App model action) -> IO ()
- Miso: startApp :: Eq model => App model action -> JSM ()
+ Miso: startApp :: Eq model => Events -> App model action -> IO ()
- Miso.Effect: (#>) :: JSM action -> model -> Effect action model
+ Miso.Effect: (#>) :: IO action -> model -> Effect parent model action
- Miso.Effect: (<#) :: model -> JSM action -> Effect action model
+ Miso.Effect: (<#) :: model -> IO action -> Effect parent model action
- Miso.Effect: mapSub :: (actionA -> actionB) -> Sub actionA -> Sub actionB
+ Miso.Effect: mapSub :: (a -> b) -> Sub a -> Sub b
- Miso.Effect: type Sub action = Sink action -> JSM ()
+ Miso.Effect: type Sub action = Sink action -> IO ()
- Miso.Event.Types: KeyInfo :: !KeyCode -> !Bool -> KeyInfo
+ Miso.Event.Types: KeyInfo :: !KeyCode -> !Bool -> !Bool -> !Bool -> !Bool -> KeyInfo
- Miso.Event.Types: defaultEvents :: Map MisoString Bool
+ Miso.Event.Types: defaultEvents :: Events
- Miso.FFI: addEventListener :: JSVal -> MisoString -> (JSVal -> JSM ()) -> JSM ()
+ Miso.FFI: addEventListener :: JSVal -> MisoString -> (JSVal -> IO ()) -> IO Function
- Miso.FFI: alert :: MisoString -> JSM ()
+ Miso.FFI: alert :: MisoString -> IO ()
- Miso.FFI: asyncCallback :: JSM () -> JSM Function
+ Miso.FFI: asyncCallback :: IO () -> IO JSVal
- Miso.FFI: asyncCallback1 :: (JSVal -> JSM ()) -> JSM Function
+ Miso.FFI: asyncCallback1 :: (JSVal -> IO ()) -> IO JSVal
- Miso.FFI: blur :: MisoString -> JSM ()
+ Miso.FFI: blur :: MisoString -> IO ()
- Miso.FFI: consoleLog :: MisoString -> JSM ()
+ Miso.FFI: consoleLog :: MisoString -> IO ()
- Miso.FFI: eventPreventDefault :: JSVal -> JSM ()
+ Miso.FFI: eventPreventDefault :: JSVal -> IO ()
- Miso.FFI: eventStopPropagation :: JSVal -> JSM ()
+ Miso.FFI: eventStopPropagation :: JSVal -> IO ()
- Miso.FFI: focus :: MisoString -> JSM ()
+ Miso.FFI: focus :: MisoString -> IO ()
- Miso.FFI: getElementById :: MisoString -> JSM JSVal
+ Miso.FFI: getElementById :: MisoString -> IO JSVal
- Miso.FFI: now :: JSM Double
+ Miso.FFI: now :: IO Double
- Miso.FFI: scrollIntoView :: MisoString -> JSM ()
+ Miso.FFI: scrollIntoView :: MisoString -> IO ()
- Miso.FFI: set :: ToJSVal v => MisoString -> v -> Object -> JSM ()
+ Miso.FFI: set :: ToJSVal v => MisoString -> v -> Object -> IO ()
- Miso.FFI: windowInnerHeight :: JSM Int
+ Miso.FFI: windowInnerHeight :: IO Int
- Miso.FFI: windowInnerWidth :: JSM Int
+ Miso.FFI: windowInnerWidth :: IO Int
- Miso.Html.Element: a_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: a_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: abbr_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: abbr_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: address_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: address_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: article_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: article_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: aside_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: aside_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: audio_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: audio_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: b_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: b_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: bdi_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: bdi_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: bdo_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: bdo_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: blockquote_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: blockquote_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: body_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: body_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: br_ :: [Attribute action] -> View action
+ Miso.Html.Element: br_ :: [Attribute action] -> View model action
- Miso.Html.Element: button_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: button_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: canvas_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: canvas_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: caption_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: caption_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: cite_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: cite_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: code_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: code_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: col_ :: [Attribute action] -> View action
+ Miso.Html.Element: col_ :: [Attribute action] -> View model action
- Miso.Html.Element: colgroup_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: colgroup_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: datalist_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: datalist_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: dd_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: dd_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: del_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: del_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: details_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: details_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: dfn_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: dfn_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: div_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: div_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: dl_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: dl_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: dt_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: dt_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: em_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: em_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: embed_ :: [Attribute action] -> View action
+ Miso.Html.Element: embed_ :: [Attribute action] -> View model action
- Miso.Html.Element: fieldset_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: fieldset_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: figcaption_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: figcaption_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: figure_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: figure_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: footer_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: footer_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: form_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: form_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: h1_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: h1_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: h2_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: h2_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: h3_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: h3_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: h4_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: h4_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: h5_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: h5_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: h6_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: h6_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: header_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: header_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: hr_ :: [Attribute action] -> View action
+ Miso.Html.Element: hr_ :: [Attribute action] -> View model action
- Miso.Html.Element: i_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: i_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: iframe_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: iframe_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: img_ :: [Attribute action] -> View action
+ Miso.Html.Element: img_ :: [Attribute action] -> View model action
- Miso.Html.Element: input_ :: [Attribute action] -> View action
+ Miso.Html.Element: input_ :: [Attribute action] -> View model action
- Miso.Html.Element: ins_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: ins_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: kbd_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: kbd_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: label_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: label_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: legend_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: legend_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: li_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: li_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: link_ :: [Attribute action] -> View action
+ Miso.Html.Element: link_ :: [Attribute action] -> View model action
- Miso.Html.Element: main_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: main_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: mark_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: mark_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: menu_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: menu_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: meter_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: meter_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: nav_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: nav_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: nodeHtml :: MisoString -> [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: nodeHtml :: MisoString -> [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: object_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: object_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: ol_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: ol_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: optgroup_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: optgroup_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: option_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: option_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: output_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: output_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: p_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: p_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: pre_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: pre_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: progress_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: progress_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: q_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: q_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: rp_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: rp_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: rt_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: rt_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: ruby_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: ruby_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: s_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: s_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: samp_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: samp_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: script_ :: [Attribute action] -> MisoString -> View action
+ Miso.Html.Element: script_ :: [Attribute action] -> MisoString -> View model action
- Miso.Html.Element: section_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: section_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: select_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: select_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: small_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: small_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: source_ :: [Attribute action] -> View action
+ Miso.Html.Element: source_ :: [Attribute action] -> View model action
- Miso.Html.Element: span_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: span_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: strong_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: strong_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: style_ :: [Attribute action] -> MisoString -> View action
+ Miso.Html.Element: style_ :: [Attribute action] -> MisoString -> View model action
- Miso.Html.Element: sub_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: sub_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: summary_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: summary_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: sup_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: sup_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: table_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: table_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: tbody_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: tbody_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: td_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: td_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: textarea_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: textarea_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: tfoot_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: tfoot_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: th_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: th_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: thead_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: thead_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: time_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: time_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: tr_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: tr_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: track_ :: [Attribute action] -> View action
+ Miso.Html.Element: track_ :: [Attribute action] -> View model action
- Miso.Html.Element: u_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: u_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: ul_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: ul_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: var_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: var_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: video_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: video_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Html.Element: wbr_ :: [Attribute action] -> View action
+ Miso.Html.Element: wbr_ :: [Attribute action] -> View model action
- Miso.Html.Event: onDrop :: AllowDrop -> action -> Attribute action
+ Miso.Html.Event: onDrop :: Options -> action -> Attribute action
- Miso.Html.Property: async_ :: MisoString -> Attribute action
+ Miso.Html.Property: async_ :: Bool -> Attribute action
- Miso.Html.Property: defer_ :: MisoString -> Attribute action
+ Miso.Html.Property: defer_ :: Bool -> Attribute action
- Miso.Html.Property: disabled_ :: Bool -> Attribute action
+ Miso.Html.Property: disabled_ :: Attribute action
- Miso.Html.Property: ismap_ :: MisoString -> Attribute action
+ Miso.Html.Property: ismap_ :: Bool -> Attribute action
- Miso.Html.Property: reversed_ :: MisoString -> Attribute action
+ Miso.Html.Property: reversed_ :: Bool -> Attribute action
- Miso.Mathml.Element: nodeMathml :: MisoString -> [Attribute action] -> [View action] -> View action
+ Miso.Mathml.Element: nodeMathml :: MisoString -> [Attribute action] -> [View model action] -> View model action
- Miso.Router: route :: HasRouter layout => Proxy layout -> RouteT layout a -> URI -> Either RoutingError a
+ Miso.Router: route :: Router route => URI -> Either RoutingError route
- Miso.Subscription.History: URI :: String -> Maybe URIAuth -> String -> String -> String -> URI
+ Miso.Subscription.History: URI :: MisoString -> MisoString -> Map MisoString (Maybe MisoString) -> URI
- Miso.Subscription.History: [uriFragment] :: URI -> String
+ Miso.Subscription.History: [uriFragment] :: URI -> MisoString
- Miso.Subscription.History: [uriPath] :: URI -> String
+ Miso.Subscription.History: [uriPath] :: URI -> MisoString
- Miso.Subscription.History: back :: JSM ()
+ Miso.Subscription.History: back :: IO ()
- Miso.Subscription.History: data () => URI
+ Miso.Subscription.History: data URI
- Miso.Subscription.History: forward :: JSM ()
+ Miso.Subscription.History: forward :: IO ()
- Miso.Subscription.History: go :: Int -> JSM ()
+ Miso.Subscription.History: go :: Int -> IO ()
- Miso.Subscription.History: pushURI :: URI -> JSM ()
+ Miso.Subscription.History: pushURI :: URI -> IO ()
- Miso.Subscription.History: replaceURI :: URI -> JSM ()
+ Miso.Subscription.History: replaceURI :: URI -> IO ()
- Miso.Subscription.Keyboard: keyboardSub :: (Set Int -> action) -> Sub action
+ Miso.Subscription.Keyboard: keyboardSub :: (IntSet -> action) -> Sub action
- Miso.Subscription.Mouse: mouseSub :: ((Int, Int) -> action) -> Sub action
+ Miso.Subscription.Mouse: mouseSub :: (PointerEvent -> action) -> Sub action
- Miso.Subscription.Window: windowCoordsSub :: ((Int, Int) -> action) -> Sub action
+ Miso.Subscription.Window: windowCoordsSub :: (Coord -> action) -> Sub action
- Miso.Subscription.Window: windowSubWithOptions :: Options -> MisoString -> Decoder r -> (r -> action) -> Sub action
+ Miso.Subscription.Window: windowSubWithOptions :: Options -> MisoString -> Decoder result -> (result -> action) -> Sub action
- Miso.Svg.Element: animateMotion_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: animateMotion_ :: [Attribute action] -> View model action
- Miso.Svg.Element: animateTransform_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: animateTransform_ :: [Attribute action] -> View model action
- Miso.Svg.Element: animate_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: animate_ :: [Attribute action] -> View model action
- Miso.Svg.Element: circle_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: circle_ :: [Attribute action] -> View model action
- Miso.Svg.Element: clipPath_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: clipPath_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: defs_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: defs_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: desc_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: desc_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: ellipse_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: ellipse_ :: [Attribute action] -> View model action
- Miso.Svg.Element: feBlend_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feBlend_ :: [Attribute action] -> View model action
- Miso.Svg.Element: feColorMatrix_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feColorMatrix_ :: [Attribute action] -> View model action
- Miso.Svg.Element: feComponentTransfer_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feComponentTransfer_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: feComposite_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feComposite_ :: [Attribute action] -> View model action
- Miso.Svg.Element: feConvolveMatrix_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feConvolveMatrix_ :: [Attribute action] -> View model action
- Miso.Svg.Element: feDiffuseLighting_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feDiffuseLighting_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: feDisplacementMap_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feDisplacementMap_ :: [Attribute action] -> View model action
- Miso.Svg.Element: feDistantLight_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feDistantLight_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: feFlood_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feFlood_ :: [Attribute action] -> View model action
- Miso.Svg.Element: feFuncA_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feFuncA_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: feFuncB_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feFuncB_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: feFuncG_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feFuncG_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: feFuncR_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feFuncR_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: feGaussianBlur_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feGaussianBlur_ :: [Attribute action] -> View model action
- Miso.Svg.Element: feImage_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feImage_ :: [Attribute action] -> View model action
- Miso.Svg.Element: feMergeNode_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feMergeNode_ :: [Attribute action] -> View model action
- Miso.Svg.Element: feMerge_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feMerge_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: feOffset_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feOffset_ :: [Attribute action] -> View model action
- Miso.Svg.Element: fePointLight_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: fePointLight_ :: [Attribute action] -> View model action
- Miso.Svg.Element: feSpecularLighting_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feSpecularLighting_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: feSpotLight_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feSpotLight_ :: [Attribute action] -> View model action
- Miso.Svg.Element: feTile_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feTile_ :: [Attribute action] -> View model action
- Miso.Svg.Element: feTurbulence_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: feTurbulence_ :: [Attribute action] -> View model action
- Miso.Svg.Element: filter_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: filter_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: foreignObject_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: foreignObject_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: g_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: g_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: image_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: image_ :: [Attribute action] -> View model action
- Miso.Svg.Element: line_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: line_ :: [Attribute action] -> View model action
- Miso.Svg.Element: linearGradient_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: linearGradient_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: marker_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: marker_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: mask_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: mask_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: metadata_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: metadata_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: mpath_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: mpath_ :: [Attribute action] -> View model action
- Miso.Svg.Element: path_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: path_ :: [Attribute action] -> View model action
- Miso.Svg.Element: pattern_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: pattern_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: polygon_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: polygon_ :: [Attribute action] -> View model action
- Miso.Svg.Element: polyline_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: polyline_ :: [Attribute action] -> View model action
- Miso.Svg.Element: radialGradient_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: radialGradient_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: rect_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: rect_ :: [Attribute action] -> View model action
- Miso.Svg.Element: script_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: script_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: set_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: set_ :: [Attribute action] -> View model action
- Miso.Svg.Element: stop_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: stop_ :: [Attribute action] -> View model action
- Miso.Svg.Element: style_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: style_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: svg_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: svg_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: switch_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: switch_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: symbol_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: symbol_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: textPath_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: textPath_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: text_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: text_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: title_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: title_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: tspan_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: tspan_ :: [Attribute action] -> [View model action] -> View model action
- Miso.Svg.Element: use_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: use_ :: [Attribute action] -> View model action
- Miso.Svg.Element: view_ :: [Attribute action] -> [View action] -> View action
+ Miso.Svg.Element: view_ :: [Attribute action] -> View model action
- Miso.Types: [logLevel] :: App model action -> LogLevel
+ Miso.Types: [logLevel] :: Component parent model action -> LogLevel
- Miso.Types: [model] :: App model action -> model
+ Miso.Types: [model] :: Component parent model action -> model
- Miso.Types: [mountPoint] :: App model action -> Maybe MisoString
+ Miso.Types: [mountPoint] :: Component parent model action -> Maybe MountPoint
- Miso.Types: [subs] :: App model action -> [Sub action]
+ Miso.Types: [subs] :: Component parent model action -> [Sub action]
- Miso.Types: [update] :: App model action -> action -> model -> Effect action model
+ Miso.Types: [update] :: Component parent model action -> action -> Effect parent model action
- Miso.Types: [view] :: App model action -> model -> View action
+ Miso.Types: [view] :: Component parent model action -> model -> View model action
- Miso.Util: (=:) :: k -> a -> Map k a
+ Miso.Util: (=:) :: k -> v -> (k, v)
- Miso.Util: conditionalViews :: Bool -> [View action] -> [View action]
+ Miso.Util: conditionalViews :: Bool -> [view] -> [view]
Files
- LICENSE +1/−1
- README.md +331/−377
- cbits/foreign.c +27/−0
- ffi/ghc/Miso/DSL/FFI.hs +203/−0
- ffi/js/Miso/DSL/FFI.hs +432/−0
- ffi/wasm/Data/JSString.hs +920/−0
- ffi/wasm/Miso/DSL/FFI.hs +480/−0
- ffi/wasm/Miso/DSL/TH.hs +40/−0
- ffi/wasm/Miso/DSL/TH/File.hs +20/−0
- js/miso.js +1084/−0
- js/miso.prod.js +1/−0
- jsbits/delegate.js +0/−140
- jsbits/diff.js +0/−360
- jsbits/isomorphic.js +0/−97
- jsbits/util.js +0/−14
- jsstring-src/Miso/String.hs +0/−149
- miso.cabal +164/−116
- src/Miso.hs +859/−190
- src/Miso/Binding.hs +123/−0
- src/Miso/CSS.hs +1424/−0
- src/Miso/CSS/Color.hs +1836/−0
- src/Miso/CSS/Types.hs +75/−0
- src/Miso/Canvas.hs +634/−0
- src/Miso/Concurrent.hs +43/−26
- src/Miso/DSL.hs +759/−0
- src/Miso/Data/Array.hs +147/−0
- src/Miso/Data/Map.hs +84/−0
- src/Miso/Data/Set.hs +112/−0
- src/Miso/Date.hs +367/−0
- src/Miso/Delegate.hs +46/−20
- src/Miso/Dev.hs +0/−14
- src/Miso/Diff.hs +31/−36
- src/Miso/Effect.hs +367/−80
- src/Miso/Effect/DOM.hs +0/−17
- src/Miso/Effect/Storage.hs +0/−125
- src/Miso/Event.hs +173/−6
- src/Miso/Event/Decoder.hs +77/−43
- src/Miso/Event/Types.hs +240/−55
- src/Miso/EventSource.hs +66/−0
- src/Miso/FFI.hs +106/−284
- src/Miso/FFI/History.hs +0/−57
- src/Miso/FFI/Internal.hs +1171/−0
- src/Miso/FFI/QQ.hs +140/−0
- src/Miso/FFI/SSE.hs +0/−39
- src/Miso/FFI/Storage.hs +0/−55
- src/Miso/FFI/WebSocket.hs +0/−68
- src/Miso/Fetch.hs +642/−0
- src/Miso/Html.hs +19/−15
- src/Miso/Html/Element.hs +530/−372
- src/Miso/Html/Event.hs +511/−82
- src/Miso/Html/Property.hs +444/−297
- src/Miso/Html/Render.hs +222/−0
- src/Miso/Html/Types.hs +0/−423
- src/Miso/Hydrate.hs +27/−0
- src/Miso/JSBits.hs +0/−1
- src/Miso/JSON.hs +831/−0
- src/Miso/JSON/Lexer.hs +109/−0
- src/Miso/JSON/Parser.hs +83/−0
- src/Miso/JSON/Types.hs +116/−0
- src/Miso/Lens.hs +897/−0
- src/Miso/Lens/TH.hs +142/−0
- src/Miso/Mathml.hs +14/−6
- src/Miso/Mathml/Element.hs +223/−12
- src/Miso/Mathml/Property.hs +232/−0
- src/Miso/Media.hs +261/−0
- src/Miso/Navigator.hs +154/−0
- src/Miso/Prelude.hs +47/−0
- src/Miso/Property.hs +83/−0
- src/Miso/PubSub.hs +22/−0
- src/Miso/Random.hs +89/−0
- src/Miso/Reload.hs +195/−0
- src/Miso/Router.hs +581/−202
- src/Miso/Runtime.hs +1842/−0
- src/Miso/Runtime/Internal.hs +31/−0
- src/Miso/State.hs +41/−0
- src/Miso/Storage.hs +140/−0
- src/Miso/String.hs +188/−0
- src/Miso/String/QQ.hs +46/−0
- src/Miso/Subscription.hs +13/−7
- src/Miso/Subscription/History.hs +102/−89
- src/Miso/Subscription/Keyboard.hs +78/−69
- src/Miso/Subscription/Mouse.hs +14/−19
- src/Miso/Subscription/OnLine.hs +36/−0
- src/Miso/Subscription/SSE.hs +0/−49
- src/Miso/Subscription/Util.hs +35/−0
- src/Miso/Subscription/WebSocket.hs +0/−168
- src/Miso/Subscription/Window.hs +61/−46
- src/Miso/Svg.hs +9/−10
- src/Miso/Svg/Attribute.hs +0/−1038
- src/Miso/Svg/Element.hs +274/−362
- src/Miso/Svg/Event.hs +41/−51
- src/Miso/Svg/Property.hs +887/−0
- src/Miso/TypeLevel.hs +0/−19
- src/Miso/Types.hs +622/−122
- src/Miso/Util.hs +99/−18
- src/Miso/Util/Lexer.hs +231/−0
- src/Miso/Util/Parser.hs +146/−0
- src/Miso/WebSocket.hs +191/−92
- tests/Main.hs +0/−178
- text-src/Miso/String.hs +0/−103
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2016-2020, David M. Johnson+Copyright (c) 2016-2026, David M. Johnson All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
README.md view
@@ -1,513 +1,467 @@ <h1 align="center">miso</h1>+ <p align="center"> <a href="https://haskell-miso.org"> <img width=10% src="https://em-content.zobj.net/thumbs/240/apple/325/steaming-bowl_1f35c.png">+ </a>-<p align="center">A <i>tasty</i> <a href="https://www.haskell.org/"><strong>Haskell</strong></a> front-end web framework</p>+<p align="center">A <i>tasty</i> <a href="https://www.haskell.org/"><strong>Haskell</strong></a> web and <a href="https://github.com/haskell-miso/miso-lynx">mobile</a> framework 🍜</p> </p> -<p align="center">- <a href="https://join.slack.com/t/haskell-miso/shared_invite/zt-1w80x404h-AF2Be_BDQixNMadzadnUNg">-<img src="https://img.shields.io/badge/slack-miso-E01563.svg?style=flat-square" alt="Miso Slack">- </a>- <a href="https://haskell.org">- <img src="https://img.shields.io/badge/language-Haskell-orange.svg?style=flat-square" alt="Haskell">+<p align="center"> + <a href="https://matrix.to/#/#haskell-miso:matrix.org">+ <img src="https://img.shields.io/badge/matrix.org-miso-FF4B33.svg?style=for-the-badge" alt="Matrix #haskell-miso:matrix.org"> </a>- <a href="https://miso-haskell.cachix.org">- <img src="https://img.shields.io/badge/build-cachix-yellow.svg?style=flat-square" alt="Cachix">+ <a href="https://www.npmjs.com/package/haskell-miso"> + <img src="https://img.shields.io/npm/v/haskell-miso?style=for-the-badge" />+ </a> + <a href="https://haskell-miso-cachix.cachix.org">+ <img src="https://img.shields.io/badge/build-cachix-yellow.svg?style=for-the-badge" alt="Cachix"> </a>- <a href="https://github.com/dmjio/miso/actions">- <img src="https://github.com/dmjio/miso/workflows/test%20matrix/badge.svg" alt="GitHub Actions">+ <a href="https://actions-badge.atrox.dev/dmjio/miso/goto?ref=master">+ <img alt="Build Status" src="https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fdmjio%2Fmiso%2Fbadge%3Fref%3Dmaster&style=for-the-badge" /> </a> <a href="http://hackage.haskell.org/package/miso">- <img src="https://img.shields.io/hackage/v/miso.svg?style=flat-square" alt="Hackage">- </a>- <a href="https://www.irccloud.com/invite?channel=%23haskell-miso&hostname=irc.libera.chat&port=6697&ssl=1">- <img src="https://img.shields.io/badge/irc-%23haskell--miso-1e72ff.svg?style=flat-square" alt="IRC #haskell-miso">- </a>- <a href="https://github.com/dmjio/miso/blob/master/LICENSE">- <img src="http://img.shields.io/badge/license-BSD3-blueviolet.svg?style=flat-square" alt="LICENSE">+ <img src="https://img.shields.io/hackage/v/miso.svg?style=for-the-badge" alt="Hackage"> </a> </p> -**Miso** is a small, production-ready, "[isomorphic](http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/)" [Haskell](https://www.haskell.org/) front-end framework for quickly building highly interactive single-page web applications. It features a virtual-dom, recursive diffing / patching algorithm, attribute and property normalization, event delegation, event batching, SVG, Server-sent events, Websockets, type-safe [servant](https://haskell-servant.github.io/)-style routing and an extensible Subscription-based subsystem. Inspired by [Elm](http://elm-lang.org/), [Redux](http://redux.js.org/) and [Bobril](http://github.com/bobris/bobril). **Miso** is pure by default, but side effects (like `XHR`) can be introduced into the system via the `Effect` data type. **Miso** makes heavy use of the [GHCJS](https://github.com/ghcjs/ghcjs) FFI and therefore has minimal dependencies. **Miso** can be considered a shallow [embedded domain-specific language](https://wiki.haskell.org/Embedded_domain_specific_language) for modern web programming.+## +**Miso** is a small, production-ready, component-oriented, [reactive](https://github.com/haskell-miso/miso-reactive), [isomorphic](http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/) [Haskell](https://www.haskell.org/) front-end framework for quickly building highly interactive single-page web and [mobile](https://github.com/dmjio/miso-native) applications. It features a virtual-dom, recursive diffing / patching algorithm, attribute and property normalization, event delegation, event batching, SVG, 2D/3D Canvas (WebGL), Server-sent events ([SSE](https://github.com/haskell-miso/miso-sse)), [Websockets](https://github.com/haskell-miso/miso-websocket), type-safe [servant](https://haskell-servant.github.io/)-style routing and an extensible Subscription-based subsystem. Inspired by [Elm](http://elm-lang.org/) and [React](http://react.dev/). **Miso** is pure by default, but side effects can be introduced into the system via the `Effect` data type.++**Miso** makes heavy use of the [GHC Javascript FFI](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/wasm.html#javascript-ffi-in-the-wasm-backend) and therefore has minimal dependencies. **Miso** can be considered a shallow [embedded domain-specific language](https://wiki.haskell.org/Embedded_domain_specific_language) for modern web programming.++**Miso** supports compilation to both [JavaScript](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/javascript.html) and [WebAssembly](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/wasm.html) using [GHC](https://www.haskell.org/ghc/). For hot-reload, `miso` uses [WASM browser mode](https://www.tweag.io/blog/2025-04-17-wasm-ghci-browser/). When used with [ghciwatch](https://github.com/MercuryTechnologies/ghciwatch) this enables a rapid development workflow.++> [!IMPORTANT]+> Check out the new [Haskell miso Organization](https://github.com/haskell-miso) 🍜+ ## Table of Contents-- [Quick Start](#quick-start)- - [Begin](#begin)- - [Nix](#nix)- - [Architecture](#architecture)- - [Under the hood](#under-the-hood)-- [Examples](#examples)- - [TodoMVC](#todomvc)- - [Flatris](#flatris)- - [2048](#2048)- - [Snake](#snake)- - [Mario](#mario)- - [Miso Plane (Flappy Birds)](#miso-plane-flappy-birds)- - [Websocket](#websocket)- - [SSE](#sse)- - [XHR](#xhr)- - [Router](#router)- - [SVG](#svg)- - [Canvas 2D](#canvas-2d)- - [ThreeJS](#threejs)- - [Simple](#simple)- - [File Reader](#file-reader)- - [WebVR](#webvr)- - [Pixel Card Wars](#pixel-card-wars)- - [Currency Converter](#currency-converter)+- [History](#history-)+- [Docs](#docs-)+- [Quick Start](#quick-start-)+- [Getting Started](#getting-started)+- [Setup](#setup-%EF%B8%8F)+- [Hot Reload](#hot-reload-) - [Haddocks](#haddocks)- - [GHC](#ghc)- - [GHCJS](#ghcjs)-- [Sample Application](#sample-application)-- [Transition Application](#transition-application)-- [Live reload with JSaddle](#live-reload-with-jsaddle)-- [Docker](#docker)+- [Wiki](#wiki)+- [Architecture](#architecture)+- [Examples](#examples) - [Building examples](#building-examples)-- [Coverage](#coverage)-- [Isomorphic](#isomorphic)-- [Pinning nixpkgs](#pinning-nixpkgs)-- [Binary cache](#binary-cache)-- [Benchmarks](#benchmarks)+- [HTTP](#interacting-with-http-apis-)+- [Coverage](#coverage-)+- [Native](#native)+- [Benchmarks](#benchmarks-%EF%B8%8F)+- [Nix](#nix-)+ - [Pinning nixpkgs](#pinning-nixpkgs-)+ - [Binary cache](#binary-cache)+- [Community](#community-) - [Maintainers](#maintainers)-- [Commercial Users](#commercial-users)+- [Commercial](#commercial-) - [Contributing](#contributing)-- [Contributors](#contributors)+- [Contributors](#contributors-)+- [Partnerships](#partnerships-)+- [Backers](#backers)+- [Organizations](#organizations) - [License](#license) -## Quick start-To get started quickly building applications, we recommend using the [`nix`](https://nixos.org/nix) package manager with miso's binary cache provided by [`cachix`](https://miso-haskell.cachix.org/). It is possible to use [`stack`](https://docs.haskellstack.org/en/stable/README/) to build GHCJS projects, but support for procuring `GHCJS` has been removed [as of stack 2.0](https://github.com/commercialhaskell/stack/issues/4086). `nix` is used to procure a working version of `GHCJS`. If you're using `cabal` we assume you have [obtained `GHCJS`](https://github.com/ghcjs/ghcjs#installation) by other means. All source code depicted below for the quick start app is available [here](https://github.com/dmjio/miso/tree/master/sample-app).--### Begin-To build the sample-app with `nix`, execute the commands below:--```bash-# optional use of cache-nix-env -iA cachix -f https://cachix.org/api/v1/install-# optional use of cache-cachix use miso-haskell-git clone https://github.com/dmjio/miso-cd miso/sample-app-nix-build-open ./result/bin/app.jsexe/index.html-```--The above commands will add miso's binary cache to your nix installation (support for both Linux and OSX).-`nix-build` will fetch the dependencies from miso's cache and build the sample application.--### Nix-`Nix` is a more powerful option for building web applications with `miso` since it encompasses development workflow, configuration management, and deployment. The source code for [`haskell-miso.org`](https://github.com/dmjio/miso/tree/master/examples/haskell-miso.org) is an example of this.--If unfamiliar with `nix`, we recommend [@Gabriella439](https://github.com/Gabriella439)'s ["Nix and Haskell in production"](https://github.com/Gabriella439/haskell-nix) guide.--To begin, make the following directory layout:-```bash-➜ mkdir app && touch app/{Main.hs,app.cabal,default.nix} && tree app-app-|-- Main.hs-|-- app.cabal-`-- default.nix-```--Add a `cabal` file-```bash-➜ cat app/*.cabal-name: app-version: 0.1.0.0-synopsis: First miso app-category: Web-build-type: Simple-cabal-version: >=1.10--executable app- main-is: Main.hs- ghcjs-options:- -dedupe- build-depends: base, miso- default-language: Haskell2010-```+# History 📜 -Write a `default.nix` (this will fetch a recent version of `miso`). `miso` will provide you with a working `nixpkgs` named `pkgs`. `callCabal2nix` will automatically produce a nix expression that builds your cabal file.+> **miso** is a play on the words ***micro*** and ***isomorphic***. -```nix-with (import (builtins.fetchGit {- url = "https://github.com/dmjio/miso";- ref = "refs/tags/1.8";-}) {});-pkgs.haskell.packages.ghcjs.callCabal2nix "app" ./. {}-```+[miso](https://haskell-miso.org) began in 2016 as research in:+ - Expressing the [Elm architecture](https://elm-lang.org) in [GHCJS](https://github.com/ghcjs/ghcjs) as an [embedded domain-specific language](https://wiki.haskell.org/Embedded_domain_specific_language).+ - Implementing modern JavaScript frontend techniques as found in [react](https://react.dev) (e.g. [Reconciliation](https://legacy.reactjs.org/docs/reconciliation.html#the-diffing-algorithm), [isomorphic](https://en.wikipedia.org/wiki/Isomorphic_JavaScript)) -Add the source from [Sample Application](#sample-application) to `app/Main.hs`+Miso aims to [bridge the gap](https://wiki.haskell.org/The_JavaScript_Problem) between modern JavaScript frameworks (such as [React](https://reactjs.org), [Vue.js](https://vuejs.org), etc.) and functional programming in [Haskell](https://haskell.org). It has since grown to encompass more features from the JavaScript community like [Components](https://react.dev/learn/your-first-component) and [Renderers](https://github.com/chentsulin/awesome-react-renderer). Miso also now supports [native development](https://github.com/haskell-miso/miso-lynx) for [iOS](https://www.apple.com/ios/), [Android](https://www.android.com/) and [HarmonyOS](https://device.harmonyos.com/en/) devices via [LynxJS](https://lynxjs.org) and targets additional backends like [Web Assembly](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/wasm.html). -Build the project-```-nix-build-```+> [!Note]+> [React-style Components](https://github.com/dmjio/miso/pull/766) are now added to `miso` as of version `1.9`. This has not yet been released, we recommend developing against `master` if you'd like to use latest features. -Open the result-```-open ./result/bin/app.jsexe/index.html-```+## Docs 📚+ +See the [Miso](https://haddocks.haskell-miso.org/miso/Miso.html) module. -For development with `nix`, it can be nice to have `cabal` present for building. This command will make it available in your `PATH`.-```-nix-env -iA cabal-install -f '<nixpkgs>'-```+## Quick start ⚡ -To be put into a shell w/ `GHCJS` and all the dependencies for this project present, use `nix-shell`.-```-nix-shell -A env-```+> [!TIP]+> We have a [template repository](https://github.com/haskell-miso/miso-sampler) that includes a sample counter application and build scripts for all platforms. -To view the dependencies for your project, call `ghcjs-pkg list` when inside the shell.-```-nix-shell -A env --run 'ghcjs-pkg list'-```+```bash+# Install nix +curl -L https://nixos.org/nix/install | sh -To build the project with `cabal` after entering the `nix-shell`-```-nix-shell -A env --run 'cabal configure --ghcjs && cabal build'-```+# Enable flakes+echo 'experimental-features = nix-command flakes' >> ~/.config/nix/nix.conf -For incremental development inside of the `nix-shell` we recommend using a tool like [`entr`](http://eradman.com/entrproject/) to automatically rebuild on file changes, or roll your own solution with `inotify`.-```-ag -l | entr sh -c 'cabal build'+# Clone, build and host+git clone https://github.com/haskell-miso/miso-sampler && cd miso-sampler+nix develop .#wasm --command bash -c 'make && make serve' ``` -### Architecture-For constructing client and server applications, we recommend using one `cabal` file with two executable sections, where the `buildable` attribute set is contingent on the compiler. An example of this layout is [here](https://github.com/dmjio/miso/blob/master/examples/haskell-miso.org/haskell-miso.cabal#L16-L60). For more info on how to use `stack` with a `client`/`server` setup, see this [link](https://docs.haskellstack.org/en/stable/ghcjs/#project-with-both-client-and-server). For more information on how to use `nix` with a `client`/`server` setup, see the [nix scripts](https://github.com/dmjio/miso/blob/master/examples/haskell-miso.org/default.nix) for [https://haskell-miso.org](https://haskell-miso.org).--## Under the hood--For details of the internals and general overview of how `miso` works, see the [Internals](docs/Internals.md).--## Examples--### TodoMVC- - [Link](https://todo-mvc.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/todo-mvc/Main.hs)--### Flatris- - [Link](https://flatris.haskell-miso.org/) / [Source](https://github.com/ptigwe/hs-flatris/)--### 2048- - [Link](https://2048.haskell-miso.org/) / [Source](https://github.com/ptigwe/hs2048/)--### Snake- - [Link](https://snake.haskell-miso.org/) / [Source](https://github.com/lbonn/miso-snake)+The fastest way to get started is to clone and build the [miso sampler](https://github.com/haskell-miso/miso-sampler) repository 🍱 This has build scripts for Web Assembly, JS and vanilla [GHC](https://haskell.org/ghc). This requires [Nix Flakes](https://wiki.nixos.org/wiki/Flakes) usage. See also the section on using [miso's binary cache](#binary-cache). -### Mario- - [Link](https://mario.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/mario/Main.hs)+## Getting started -### Miso Plane (Flappy Birds)- - [Link](http://miso-plane.haskell-miso.org) / [Source](https://github.com/Lermex/miso-plane)+To start developing applications with `miso` you will need to acquire [GHC](https://www.haskell.org/ghc/) and [cabal](https://www.haskell.org/cabal/). This can be done via [GHCup](https://www.haskell.org/ghcup/) or [Nix](https://nixos.org/). -### Websocket- - [Link](https://websocket.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/websocket/Main.hs)+> [!TIP]+> For new Haskell users we recommend using [GHCup](https://www.haskell.org/ghcup/) to acquire both [GHC](https://www.haskell.org/ghc/) and [cabal](https://www.haskell.org/cabal/) -### SSE- - [Link](http://sse.haskell-miso.org/) / [Client](https://github.com/dmjio/miso/blob/master/examples/sse/client/Main.hs) / [Server](https://github.com/dmjio/miso/blob/master/examples/sse/server/Main.hs)+## Setup 🏗️ -### XHR- - [Link](https://xhr.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/xhr/Main.hs)+To develop and build your first `miso` application you will need 3 files: -### Router- - [Link](https://router.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/router/Main.hs)+ - `cabal.project`+ - `app.cabal`+ - `Main.hs` -### SVG- - [Link](https://svg.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/svg/Main.hs)+### `cabal.project` -### Canvas 2D- - [Link](https://canvas.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/canvas2d/Main.hs)+```yaml+packages:+ . -### ThreeJS- - [Link](https://threejs.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/three/Main.hs)+source-repository-package+ type: git+ location: https://github.com/dmjio/miso+ branch: master+``` -### Simple- - [Link](https://simple.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/simple/Main.hs)+### `app.cabal` -### File Reader- - [Link](https://file-reader.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/file-reader/Main.hs)+We recommend using at least `cabal-version: 2.2`, this will give you the [common sections](https://vrom911.github.io/blog/common-stanzas) feature which we will use later to allow multiple compilers to build our project (so we can target `WASM` and `JS` backends) -### WebVR- - [Link](http://fizruk.github.io/fpconf-2017-talk/miso-aframe-demo/dist/demo.jsexe/index.html) / [Source](https://github.com/fizruk/miso-aframe)+```yaml+cabal-version: 2.2+name: app+version: 0.1.0.0+synopsis: Sample miso app+category: Web -### Pixel Card Wars- - [Link](https://smelc3.itch.io/pixel-card-wars) / [Source](https://github.com/smelc/miso-darkcraw)+common options+ if arch(wasm32)+ ghc-options:+ -no-hs-main+ -optl-mexec-model=reactor+ "-optl-Wl,--export=hs_start"+ cpp-options:+ -DWASM -### Currency Converter- - [Link](https://functora.github.io/apps/currency-converter) / [Source](https://github.com/functora/functora.github.io/tree/master/ghcjs/currency-converter)+ if arch(javascript)+ ld-options:+ -sEXPORTED_RUNTIME_METHODS=HEAP8 -## Haddocks+executable app+ import:+ options+ main-is:+ Main.hs+ build-depends:+ base, miso+ default-language:+ Haskell2010+``` -### GHCJS- - [Link](https://haddocks.haskell-miso.org/)+### `Main.hs` -### GHC- - [Link](http://hackage.haskell.org/package/miso)+This file contains a simple `miso` counter application. -## Sample application ```haskell--- | Haskell language pragma+---------------------------------------------------------------------------- {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}---- | Haskell module declaration+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE CPP #-}+---------------------------------------------------------------------------- module Main where---- | Miso framework import-import Miso-import Miso.String---- | Type synonym for an application model-type Model = Int---- | Sum type for application events+----------------------------------------------------------------------------+import Miso+import qualified Miso.Html as H+import qualified Miso.Html.Property as P+import Miso.Lens+----------------------------------------------------------------------------+-- | Sum type for App events data Action = AddOne | SubtractOne- | NoOp | SayHelloWorld deriving (Show, Eq)-+---------------------------------------------------------------------------- -- | Entry point for a miso application main :: IO ()-main = startApp App {..}- where- initialAction = SayHelloWorld -- initial action to be executed on application load- model = 0 -- initial model- update = updateModel -- update function- view = viewModel -- view function- events = defaultEvents -- default delegated events- subs = [] -- empty subscription list- mountPoint = Nothing -- mount point for application (Nothing defaults to 'body')- logLevel = Off -- used during prerendering to see if the VDOM and DOM are in sync (only applies to `miso` function)-+main = startApp defaultEvents app+----------------------------------------------------------------------------+-- | WASM export, required when compiling w/ the WASM backend.+#ifdef WASM+foreign export javascript "hs_start" main :: IO ()+#endif+----------------------------------------------------------------------------+-- | `component` takes as arguments the initial model, update function, view function+app :: App Int Action+app = component 0 updateModel viewModel+---------------------------------------------------------------------------- -- | Updates model, optionally introduces side effects-updateModel :: Action -> Model -> Effect Action Model-updateModel action m =- case action of- AddOne- -> noEff (m + 1)- SubtractOne- -> noEff (m - 1)- NoOp- -> noEff m- SayHelloWorld- -> m <# do consoleLog "Hello World" >> pure NoOp-+updateModel :: Action -> Effect parent Int Action+updateModel = \case+ AddOne -> this += 1+ SubtractOne -> this -= 1+ SayHelloWorld -> io_ $ do+ alert "Hello World"+ consoleLog "Hello World"+---------------------------------------------------------------------------- -- | Constructs a virtual DOM from a model-viewModel :: Model -> View Action-viewModel x = div_ [] [- button_ [ onClick AddOne ] [ text "+" ]- , text (ms x)- , button_ [ onClick SubtractOne ] [ text "-" ]- ]+viewModel :: Int -> View Int Action+viewModel x =+ H.div_+ [ P.className "counter"+ ]+ [ H.button_ [ H.onClick AddOne ] [ text "+" ]+ , text (ms x)+ , H.button_ [ H.onClick SubtractOne ] [ text "-" ]+ , H.br_ []+ , H.button_ [ H.onClick SayHelloWorld ] [ text "Alert Hello World!" ]+ ]+---------------------------------------------------------------------------- ``` -## Transition application+Now that your project files are populated, development can begin. -An alternative, more powerful interface for constructing `miso` applications is using the `Transition` interface.-`Transition` is based on the `StateT` monad transformer, and can be used to construct components. It also works-very nicely with lenses based on `MonadState` (i.e. `(.=)`, `(%=)`,`(+=)`,`(-=)`).+## Hot Reload 🔥 +See the [WASM browser mode](https://github.com/haskell-miso/miso-sampler/blob/main/README.md#browser-mode-) section of the [miso-sampler](https://github.com/haskell-miso/miso-sampler) repository for usage of hot reload development w/ [ghciwatch](https://github.com/MercuryTechnologies/ghciwatch). Also see this [blog post](https://www.tweag.io/blog/2025-04-17-wasm-ghci-browser/).+## Installation -```haskell--- | Haskell language pragma-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}+See [Installation](docs/Install.md) for more information. --- | Haskell module declaration-module Main where+## Haddocks --- | Miso framework import-import Miso-import Miso.String+Offical [Haskell](https://haskell.org) documentation of the [Miso](https://haskell-miso.org) web framework. --- | Lens import-import Control.Lens+| Platform | URL |+|------|-------------|+| GHCJS | [Link](https://haddocks.haskell-miso.org/) |+| GHC | [Link](http://hackage.haskell.org/package/miso) | --- | Type synonym for an application model-data Model- = Model- { _counter :: Int- } deriving (Show, Eq)+## Wiki -counter :: Lens' Model Int-counter = lens _counter $ \record field -> record { _counter = field }+See the [DeepWiki](https://deepwiki.com/dmjio/miso) entry to explore the source code. --- | Sum type for application events-data Action- = AddOne- | SubtractOne- | NoOp- | SayHelloWorld- deriving (Show, Eq)+[](https://deepwiki.com/dmjio/miso) --- | Entry point for a miso application-main :: IO ()-main = startApp App {..}- where- initialAction = SayHelloWorld -- initial action to be executed on application load- model = Model 0 -- initial model- update = fromTransition . updateModel -- update function- view = viewModel -- view function- events = defaultEvents -- default delegated events- subs = [] -- empty subscription list- mountPoint = Nothing -- mount point for application (Nothing defaults to 'body')- logLevel = Off -- used during prerendering to see if the VDOM and DOM are in sync (only applies to `miso` function)+## Architecture --- | Updates model, optionally introduces side effects-updateModel :: Action -> Transition Action Model ()-updateModel action =- case action of- AddOne- -> counter += 1- SubtractOne- -> counter -= 1- NoOp- -> pure ()- SayHelloWorld- -> scheduleIO_ (consoleLog "Hello World")+For constructing client and server applications, we recommend using one `cabal` file with two executable sections, where the `buildable` attribute set is contingent on the compiler. An example of this layout is [here](https://github.com/haskell-miso/haskell-miso.org/blob/master/haskell-miso.cabal). --- | Constructs a virtual DOM from a model-viewModel :: Model -> View Action-viewModel x = div_ [] [- button_ [ onClick AddOne ] [ text "+" ]- , text . ms $ x^.counter- , button_ [ onClick SubtractOne ] [ text "-" ]- ]-```+> [!TIP]+> For more information on how to use `nix` with a `client`/`server` setup, see the [nix scripts](https://github.com/haskell-miso/haskell-miso.org/blob/master/default.nix) for [https://haskell-miso.org](https://haskell-miso.org). -## Live reload with JSaddle+## Examples -It is possible to build `miso` applications with `ghcid`, `jsaddle` that allow live reloading of your application in reponse to changes in application code. See the [README](https://github.com/dmjio/miso/blob/master/sample-app-jsaddle/README.md) in the `sample-app-jsaddle` folder for more information.+For real-world examples of Haskell `miso` applications, see below. -## Docker+| Name | Description | Source Link | Live Demo Link | Author |+|-----------------------|-------------------------------------------|---------------------------------------------------------------|-----------------------------------------------------------|---------------------------------------------------|+| **TodoMVC** | A classic TodoMVC implementation | [Source](https://github.com/haskell-miso/miso-todomvc) | [Demo](https://todomvc.haskell-miso.org) | [@dmjio](https://github.com/dmjio) |+| **2048** | A clone of the 2048 game | [Source](https://github.com/haskell-miso/miso-2048) | [Demo](https://2048.haskell-miso.org/) | [@ptigwe](https://github.com/ptigwe) |+| **Flatris** | A Tetris-like game | [Source](https://github.com/haskell-miso/miso-flatris) | [Demo](https://flatris.haskell-miso.org/) | [@ptigwe](https://github.com/ptigwe) |+| **Plane** | A flappy-birds-like game | [Source](https://github.com/haskell-miso/miso-plane) | [Demo](https://plane.haskell-miso.org/) | [@Lermex](https://github.com/Lermex) |+| **Snake** | The classic Snake game | [Source](https://github.com/haskell-miso/miso-snake) | [Demo](https://snake.haskell-miso.org/) | [@lbonn](https://github.com/lbonn) |+| **SVG** | An example showcasing SVG rendering | [Source](https://github.com/haskell-miso/miso-svg) | [Demo](https://svg.haskell-miso.org/) | [@dmjio](https://github.com/dmjio) |+| **Fetch** | An example demonstrating AJAX requests | [Source](https://github.com/haskell-miso/miso-fetch) | [Demo](https://fetch.haskell-miso.org) | [@dmjio](https://github.com/dmjio) |+| **File Reader** | A FileReader API example | [Source](https://github.com/haskell-miso/miso-filereader) | [Demo](https://file-reader.haskell-miso.org/) | [@dmjio](https://github.com/dmjio) |+| **Mario** | A Super Mario physics example | [Source](https://github.com/haskell-miso/miso-mario) | [Demo](https://mario.haskell-miso.org) | [@dmjio](https://github.com/dmjio) |+| **WebSocket** | A simple WebSocket example | [Source](https://github.com/haskell-miso/miso-websocket) | [Demo](https://websocket.haskell-miso.org) | [@dmjio](https://github.com/dmjio) |+| **Router** | A client-side routing example | [Source](https://github.com/haskell-miso/miso-router) | [Demo](https://router.haskell-miso.org) | [@dmjio](https://github.com/dmjio) |+| **Canvas 2D** | A 2D Canvas rendering example | [Source](https://github.com/haskell-miso/miso-canvas2d) | [Demo](https://canvas.haskell-miso.org) | [@dmjio](https://github.com/dmjio) |+| **MathML** | A MathML example | [Source](https://github.com/haskell-miso/miso-mathml) | [Demo](https://mathml.haskell-miso.org) | [@dmjio](https://github.com/dmjio) |+| **Simple** | A simple counter example | [Source](https://github.com/haskell-miso/miso-sampler) | [Demo](https://counter.haskell-miso.org) | [@dmjio](https://github.com/dmjio) |+| **SSE** | SSE (Server-sent events) Example | [Source](https://github.com/haskell-miso/miso-sse) | [Demo](https://sse.haskell-miso.org) | [@dmjio](https://github.com/dmjio) |+| **Three.js** | A 3D rendering example using Three.JS | [Source](https://github.com/haskell-miso/three-miso) | [Demo](https://threejs.haskell-miso.org/) | [@juliendehos](https://github.com/juliendehos) |+| **Space Invaders** | A Space-Invaders-like game | [Source](https://github.com/haskell-miso/miso-invaders) | [Demo](https://space-invaders.haskell-miso.org/) | [@juliendehos](https://github.com/juliendehos) |+| **Audio** | Audio examples | [Source](https://github.com/haskell-miso/miso-audio) | [Demo](https://audio.haskell-miso.org/) | [@juliendehos](https://github.com/juliendehos) |+| **Video** | Video examples | [Source](https://github.com/haskell-miso/miso-video) | [Demo](https://video.haskell-miso.org/) | [@juliendehos](https://github.com/juliendehos) |+| **WebVR** | WebVR examples | [Source](https://github.com/haskell-miso/miso-aframe) | [Demo](https://aframe.haskell-miso.org/) | [@dmjio](https://github.com/dmjio) |+| **Reactivity** | Reactive examples | [Source](https://github.com/haskell-miso/miso-reactive) | [Demo](https://reactive.haskell-miso.org/) | [@dmjio](https://github.com/dmjio) | -Developing miso applications inside a Docker container is supported (allows applications to be built on Windows). See the [README](https://github.com/dmjio/miso/blob/master/docker/README.md) in the `docker` folder for more information. ## Building examples -The easiest way to build the examples is with the [`nix`](https://nixos.org/nix/) package manager-```-git clone https://github.com/dmjio/miso && cd miso && nix-build --arg examples true-```+The easiest way to build the examples is with the [`nix`](https://nixos.org/nix/) package manager. -This will build all examples and documentation into a folder named `result`+> [!TIP]+> Use [cachix](https://cachix.org) to ensure you're not building dependencies unnecessarily `cachix use haskell-miso-cachix`++See the [@HaskellMiso](https://github.com/haskell-miso) organization for all examples, and how to build then.++## Interacting with HTTP APIs 🔌++If you want to interact with an HTTP API, we recommend one of the following approaches:++ 1. For a simple JSON-based API, you can use Miso's [Fetch](https://haddocks.haskell-miso.org/miso/Miso-Fetch.html) module.++ 2. In more complex cases, you can define a [Servant](https://www.servant.dev/) API and automatically obtain client functions via [servant-miso-client](https://github.com/haskell-miso/servant-miso-client).++ The Fetch example ([Source](https://github.com/haskell-miso/miso-fetch), [Demo](https://fetch.haskell-miso.org/)) demonstrates the necessary ingredients. Make sure to add the following to your `cabal.project`:++ ```cabal+ source-repository-package+ type: git+ location: https://github.com/haskell-miso/servant-miso-client+ tag: master+ ```++## Coverage ✅++The core engine of `miso` is the [diff](https://github.com/dmjio/miso/blob/master/ts/miso/dom.ts) function. It is responsible for all DOM manipulation that occurs in a miso application and has [100% code coverage](http://coverage.haskell-miso.org). Tests and coverage made possible using [bun](https://github.com/oven-sh/bun).++> [!NOTE]+> To run the tests and build the coverage report ensure [bun](https://github.com/oven-sh/bun) is installed.++```bash+$ curl -fsSL https://bun.sh/install | bash ```-➜ miso git:(master) ✗ tree -d ./result/bin-./result/bin-|-- canvas2d.jsexe-|-- compose-update.jsexe-|-- file-reader.jsexe-|-- mario.jsexe-| `-- imgs-|-- mathml.jsexe-|-- router.jsexe-|-- simple.jsexe-|-- svg.jsexe-|-- tests.jsexe-|-- threejs.jsexe-|-- todo-mvc.jsexe-|-- websocket.jsexe-`-- xhr.jsexe+or++```bash+$ nix-env -iA bun -f '<nixpkgs>' ``` -To see examples, we recommend hosting them with a webserver+and +```bash+$ bun install && bun run test ```-cd result/bin/todo-mvc.jsexe && nix-shell -p python --run 'python -m SimpleHTTPServer'-Serving HTTP on 0.0.0.0 port 8000 ...++```bash+--------------------------|---------|---------|-------------------+File | % Funcs | % Lines | Uncovered Line #s+--------------------------|---------|---------|-------------------+All files | 93.50 | 92.28 |+ ts/happydom.ts | 100.00 | 100.00 |+ ts/miso/context/dom.ts | 100.00 | 100.00 |+ ts/miso/context/patch.ts | 75.00 | 81.17 | 68-76,79-84,87-93,99-107,193-202+ ts/miso/dom.ts | 100.00 | 98.86 | 41,302-303+ ts/miso/event.ts | 100.00 | 92.75 | 28-30,52,81,85-90,116,161+ ts/miso/hydrate.ts | 100.00 | 98.15 | 11-12+ ts/miso/patch.ts | 100.00 | 80.00 | 26-32,36,38,42-43,85-86,91,93+ ts/miso/smart.ts | 85.00 | 93.33 | 45-48+ ts/miso/types.ts | 100.00 | 100.00 |+ ts/miso/util.ts | 75.00 | 78.53 | 79,83,122,137,169,172,175-186,197-202,223-229,233-236,249-254+--------------------------|---------|---------|-------------------++ 223 pass+ 0 fail+ 7598 expect() calls+Ran 223 tests across 9 files. [497.00ms] ``` -## Coverage+## Native📱+Miso supports the creation of iOS and Android applications via [LynxJS](https://lynxjs.org). See the [miso-lynx](https://github.com/haskell-miso/miso-lynx) repository for more information. -The core algorithmic component of miso is [diff.js](https://github.com/dmjio/miso/blob/master/jsbits/diff.js). It is responsible for all DOM manipulation that occurs in a miso application and has [100% code coverage](http://coverage.haskell-miso.org). Tests and coverage made possible using [jsdom](https://github.com/jsdom/jsdom) and [jest](https://github.com/facebook/jest).+## Benchmarks 🏎️ -To run the tests and build the coverage report:+[According to benchmarks](https://krausest.github.io/js-framework-benchmark/current.html) `miso` is competitive. `miso.js` depicted below is how `miso` performs with its JS engine relative to vanilla JS. The `miso` column shows performance using the [GHC](https://www.haskell.org/ghc/) JS backend. We're currently researching [staged meta-programming](https://dl.acm.org/doi/abs/10.1145/3498723) as a way to remove excess allocations in our DSL and to increase performance when compiling from Haskell. -```bash-cd miso/tests-npm i-npm run test-## Or by using `yarn` instead of `npm`:-# yarn-# yarn test-```+<a target="_blank" href="https://krausest.github.io/js-framework-benchmark/current.html"><img width="657" height="739" alt="image" src="https://github.com/user-attachments/assets/c217df73-8c30-4965-977a-2e949c114291" /></a> -## Isomorphic+## Nix <img src="https://raw.githubusercontent.com/NixOS/nixos-artwork/refs/heads/master/logo/nix-snowflake-colours.svg" alt="nixos-snowflake" width="25"/> -[Isomorphic javascript](https://en.wikipedia.org/wiki/Isomorphic_JavaScript) is a technique for increased SEO, code-sharing and perceived page load times. It works in two parts. First, the server sends a pre-rendered HTML body to the client's browser. Second, after the client javascript application loads, the pointers of the pre-rendered DOM are copied into the virtual DOM, and the application proceeds as normal. All subsequent page navigation is handled locally by the client, avoiding full-page postbacks as necessary.+`Nix` is a powerful option for building web applications with `miso` since it encompasses development workflow, configuration management, and deployment. The source code for [`haskell-miso.org`](https://github.com/dmjio/miso/tree/master/haskell-miso.org) is an example of this. -The `miso` function is used to perform the pointer-copying behavior client-side.+> [!TIP]+> If unfamiliar with `nix`, we recommend [@Gabriella439](https://github.com/Gabriella439)'s ["Nix and Haskell in production"](https://github.com/Gabriella439/haskell-nix) guide. -For more information on how `miso` handles isomorphic javascript, we recommend [this tutorial](https://github.com/FPtje/miso-isomorphic-example).+### Pinning nixpkgs 📌 -## Pinning nixpkgs+By default `miso` uses a known-to-work, pinned version of [`nixpkgs`](https://github.com/dmjio/miso/blob/master/nix/nixpkgs.json) known as `pkgs`. -By default `miso` uses a known-to-work, pinned version of [`nixpkgs`](https://github.com/dmjio/miso/blob/master/nix/nixpkgs.json).+> [!NOTE]+> `miso` also maintains a legacy version of nixpkgs known as `legacyPkgs` so we can use tools like `nixops` for deployment and to build `miso` with the original `GHCJS 8.6` backend. -## Binary cache+### Binary cache -`nix` users on a Linux or OSX distro can take advantage of a [binary cache](https://miso-haskell.cachix.org) for faster builds. To use the binary cache follow the instructions on [cachix](https://miso-haskell.cachix.org/).+`nix` users on a Linux or OSX distros can take advantage of a [binary cache](https://haskell-miso-cachix.cachix.org) for faster builds. To use the binary cache follow the instructions on [cachix](https://haskell-miso-cachix.cachix.org/). +> [!TIP]+> We highly recommend nix users consume the [cachix](https://cachix.org) cache. `cachix use haskell-miso-cachix`.+ ```bash-cachix use miso-haskell+$ cachix use haskell-miso-cachix ``` -## Benchmarks+When building `miso` projects w/ GitHub workflow CI, we recommend the Cachix GitHub action -[According to benchmarks](https://krausest.github.io/js-framework-benchmark/current.html), `miso` is among the fastest functional programming web frameworks, second only to [Elm](http://elm-lang.org).+```yaml+- name: Install cachix+ uses: cachix/cachix-action@v16+ with:+ name: haskell-miso-cachix+``` -<a target="_blank" href="https://krausest.github.io/js-framework-benchmark/current.html"><img src="https://cdn-images-1.medium.com/max/1600/1*6EjJTf1mhlTxd4QWsygCwA.png" width="500" height="600" /></a>+## Community :octocat: +- [Github](https://github.com/haskell-miso)+- [Matrix](https://matrix.to/#/#haskell-miso:matrix.org)+- [Discord](https://discord.gg/QVDtfYNSxq)+- [Slack](https://haskell-miso.slack.com/join/shared_invite_confirmed/zt-37vusrcdw-HH6~hY0DGT7MLCjNWZvLDQ#/email-invite/credentials)+- [IRC](https://www.irccloud.com/invite?channel=%23haskell-miso&hostname=irc.libera.chat&port=6697&ssl=1)+ ## Maintainers [@dmjio](https://github.com/dmjio) -## Commercial Users- - [Polimorphic](https://www.polimorphic.com)- - [LumiGuide](https://lumi.guide/en/)- - [Clovyr](https://clovyr.io)+## Commercial 🚀 +Since it's launch, `miso` has been used in a variety of industries, including but not limited to:++ - Quantitative finance+ - Network security+ - Defense research+ - Academia+ - SaaS companies+ - Public sector+ - Non-profit sector+ - etc.++The largest `miso` installation known was ~200,000 lines of `miso` code with 10,000+ users.+ ## Contributing -Feel free to dive in! [Open an issue](https://github.com/dmjio/miso/issues/new) or submit [PRs](https://github.com/dmjio/miso/pulls).+Feel free to dive in! [Open an issue](https://github.com/dmjio/miso/issues/new) or a submit [Pull Request](https://github.com/dmjio/miso/pulls). See [CONTRIBUTING](https://github.com/dmjio/miso/blob/master/CONTRIBUTING.md) for more info. -## Contributors+## Contributors 🦾 -### Code Contributors+> [!NOTE]+> This project exists thanks to all the people who [contribute](CONTRIBUTING.md) -This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. <a href="https://github.com/dmjio/miso/graphs/contributors"><img src="https://opencollective.com/miso/contributors.svg?width=890&button=false" /></a> -### Financial Contributors+## Partnerships 🤝 -Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/miso/contribute)]+If you'd like to support this project financially, be it through requesting feature development, or a corporate partnership, please drop us a line and we will be in touch shortly. <p><a href="mailto:support@haskell-miso.org">support@haskell-miso.org</a></p> -#### Individuals+## Backers +Become a [financial contributor](https://opencollective.com/miso/contribute) and help us sustain our project and community. We are very grateful and thankful for our individual sponsors.++ - Moses Tschanz+ - [@MaxGabriel](https://github.com/MaxGabriel)+ - [@maybetonyfu](https://github.com/maybetonyfu)+ - [@jhrcek](https://github.com/jhrcek)+ - etc.+ <a href="https://opencollective.com/miso"><img src="https://opencollective.com/miso/individuals.svg?width=890"></a> -#### Organizations+## Organizations -Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/miso/contribute)]+[Support this project](https://opencollective.com/miso/contribute) with your organization. Your logo will show up here with a link to your website. We are also very grateful and thankful for our corporate sponsors. -<a href="https://opencollective.com/miso/organization/0/website"><img src="https://opencollective.com/miso/organization/0/avatar.svg"></a>-<a href="https://opencollective.com/miso/organization/1/website"><img src="https://opencollective.com/miso/organization/1/avatar.svg"></a>-<a href="https://opencollective.com/miso/organization/2/website"><img src="https://opencollective.com/miso/organization/2/avatar.svg"></a>-<a href="https://opencollective.com/miso/organization/3/website"><img src="https://opencollective.com/miso/organization/3/avatar.svg"></a>-<a href="https://opencollective.com/miso/organization/4/website"><img src="https://opencollective.com/miso/organization/4/avatar.svg"></a>-<a href="https://opencollective.com/miso/organization/5/website"><img src="https://opencollective.com/miso/organization/5/avatar.svg"></a>-<a href="https://opencollective.com/miso/organization/6/website"><img src="https://opencollective.com/miso/organization/6/avatar.svg"></a>-<a href="https://opencollective.com/miso/organization/7/website"><img src="https://opencollective.com/miso/organization/7/avatar.svg"></a>-<a href="https://opencollective.com/miso/organization/8/website"><img src="https://opencollective.com/miso/organization/8/avatar.svg"></a>-<a href="https://opencollective.com/miso/organization/9/website"><img src="https://opencollective.com/miso/organization/9/avatar.svg"></a>+<a target="_blank" href="https://opencollective.com/miso/organization/0/website"><img src="https://opencollective.com/miso/organization/0/avatar.svg"></a> ## License -[BSD3](LICENSE) © David Johnson+[BSD3](LICENSE) © dmjio
+ cbits/foreign.c view
@@ -0,0 +1,27 @@+#include <stdlib.h>+#include <stdint.h>++// dmj: like `foreign-store`, but just for a single Ptr.+// this is used to store a StablePtr (IORef a), retrieved after a GHCi reload++static void *stored_value = NULL;++// Store a pointer+void x_store(void *ptr) {+ stored_value = ptr;+}++// Get the stored pointer+void *x_get(void) {+ return stored_value;+}++// Check if a pointer is stored (non-NULL)+int x_exists(void) {+ return stored_value != NULL;+}++// Clear the stored pointer+void x_clear(void) {+ stored_value = NULL;+}
+ ffi/ghc/Miso/DSL/FFI.hs view
@@ -0,0 +1,203 @@+-----------------------------------------------------------------------------+module Miso.DSL.FFI where+-----------------------------------------------------------------------------+import Data.Text (Text, pack, unpack)+import Text.Read (readMaybe)+-----------------------------------------------------------------------------+-- | A type that represents any JS value+data JSVal = JSVal+-----------------------------------------------------------------------------+instance Eq JSVal where+ JSVal == JSVal = True+-----------------------------------------------------------------------------+toJSVal_Bool :: Bool -> IO JSVal+toJSVal_Bool = undefined+-----------------------------------------------------------------------------+toJSVal_Double :: Double -> IO JSVal+toJSVal_Double = undefined+-----------------------------------------------------------------------------+toJSVal_Int :: Int -> IO JSVal+toJSVal_Int = undefined+-----------------------------------------------------------------------------+toJSVal_List :: [JSVal] -> IO JSVal+toJSVal_List = undefined+-----------------------------------------------------------------------------+-- | The 'null' value in JS.+jsNull :: JSVal+jsNull = JSVal+-----------------------------------------------------------------------------+toJSVal_JSVal :: JSVal -> IO JSVal+toJSVal_JSVal = undefined+-----------------------------------------------------------------------------+toJSVal_Char :: Char -> IO JSVal+toJSVal_Char = undefined+-----------------------------------------------------------------------------+toJSVal_Float :: Float -> IO JSVal+toJSVal_Float = undefined+-----------------------------------------------------------------------------+toJSVal_Text :: Text -> IO JSVal+toJSVal_Text = undefined+-----------------------------------------------------------------------------+fromJSVal_Text :: JSVal -> IO (Maybe Text)+fromJSVal_Text = undefined+-----------------------------------------------------------------------------+fromJSValUnchecked_Text :: JSVal -> IO Text+fromJSValUnchecked_Text = undefined+-----------------------------------------------------------------------------+fromJSVal_Char :: JSVal -> IO (Maybe Char)+fromJSVal_Char = undefined+-----------------------------------------------------------------------------+fromJSValUnchecked_Char :: JSVal -> IO Char+fromJSValUnchecked_Char = undefined+-----------------------------------------------------------------------------+fromJSVal_Float :: JSVal -> IO (Maybe Float)+fromJSVal_Float = undefined+-----------------------------------------------------------------------------+fromJSValUnchecked_Float :: JSVal -> IO Float+fromJSValUnchecked_Float = undefined+-----------------------------------------------------------------------------+fromJSVal_Bool :: JSVal -> IO (Maybe Bool)+fromJSVal_Bool = undefined+-----------------------------------------------------------------------------+new_ffi :: JSVal -> JSVal -> IO JSVal+new_ffi = undefined+-----------------------------------------------------------------------------+eval_ffi :: Text -> IO JSVal+eval_ffi = undefined+-----------------------------------------------------------------------------+create_ffi :: IO JSVal+create_ffi = undefined+-----------------------------------------------------------------------------+getProp_ffi :: Text -> JSVal -> IO JSVal+getProp_ffi = undefined+-----------------------------------------------------------------------------+setProp_ffi :: Text -> JSVal -> JSVal -> IO ()+setProp_ffi = undefined+-----------------------------------------------------------------------------+setField_ffi :: JSVal -> Text -> JSVal -> IO ()+setField_ffi = undefined+-----------------------------------------------------------------------------+fromJSVal_Int :: JSVal -> IO (Maybe Int)+fromJSVal_Int = undefined+-----------------------------------------------------------------------------+fromJSVal_Double :: JSVal -> IO (Maybe Double)+fromJSVal_Double = undefined+-----------------------------------------------------------------------------+getPropIndex_ffi :: Int -> JSVal -> IO JSVal+getPropIndex_ffi = undefined+-----------------------------------------------------------------------------+isNull_ffi :: JSVal -> Bool+isNull_ffi = undefined+-----------------------------------------------------------------------------+isUndefined_ffi :: JSVal -> Bool+isUndefined_ffi = undefined+-----------------------------------------------------------------------------+freeFunction_ffi :: JSVal -> IO ()+freeFunction_ffi = undefined+-----------------------------------------------------------------------------+requestAnimationFrame :: JSVal -> IO Int+requestAnimationFrame = undefined+-----------------------------------------------------------------------------+cancelAnimationFrame :: Int -> IO ()+cancelAnimationFrame = undefined+-----------------------------------------------------------------------------+toJSVal_JSString :: Text -> IO JSVal+toJSVal_JSString = undefined+-----------------------------------------------------------------------------+fromJSValUnchecked_Maybe :: JSVal -> IO (Maybe JSVal)+fromJSValUnchecked_Maybe = undefined+-----------------------------------------------------------------------------+fromJSVal_Maybe :: JSVal -> IO (Maybe (Maybe JSVal))+fromJSVal_Maybe = undefined+-----------------------------------------------------------------------------+fromJSValUnchecked_Bool :: JSVal -> IO Bool+fromJSValUnchecked_Bool = undefined+-----------------------------------------------------------------------------+invokeFunction :: JSVal -> JSVal -> JSVal -> IO JSVal+invokeFunction = undefined+-----------------------------------------------------------------------------+listProps_ffi :: JSVal -> IO JSVal+listProps_ffi = undefined+-----------------------------------------------------------------------------+setPropIndex_ffi :: Int -> JSVal -> JSVal -> IO ()+setPropIndex_ffi = undefined+-----------------------------------------------------------------------------+-- | The @globalThis@ object in JS.+global :: JSVal+global = undefined+-----------------------------------------------------------------------------+fromJSVal_List :: JSVal -> IO (Maybe [JSVal])+fromJSVal_List = undefined+-----------------------------------------------------------------------------+fromJSValUnchecked_Int :: JSVal -> IO Int+fromJSValUnchecked_Int = undefined+-----------------------------------------------------------------------------+fromJSValUnchecked_Double :: JSVal -> IO Double+fromJSValUnchecked_Double = undefined+-----------------------------------------------------------------------------+fromJSVal_JSString :: JSVal -> IO (Maybe Text)+fromJSVal_JSString = undefined+-----------------------------------------------------------------------------+-- | A asynchronous callback+asyncCallback :: IO () -> IO JSVal+asyncCallback = undefined+-- | A asynchronous callback with one argument+asyncCallback1 :: (JSVal -> IO ()) -> IO JSVal+asyncCallback1 = undefined+-- | A asynchronous callback with two arguments+asyncCallback2 :: (JSVal -> JSVal -> IO ()) -> IO JSVal+asyncCallback2 = undefined+-- | A asynchronous callback with three arguments+asyncCallback3 :: (JSVal -> JSVal -> JSVal -> IO ()) -> IO JSVal+asyncCallback3 = undefined+-----------------------------------------------------------------------------+-- | A synchronous callback+syncCallback :: IO () -> IO JSVal+syncCallback = undefined+-- | A synchronous callback with a single argument+syncCallback1 :: (JSVal -> IO ()) -> IO JSVal+syncCallback1 = undefined+-- | A synchronous callback with two arguments+syncCallback2 :: (JSVal -> JSVal -> IO ()) -> IO JSVal+syncCallback2 = undefined+-- | A synchronous callback with three arguments+syncCallback3 :: (JSVal -> JSVal -> JSVal -> IO ()) -> IO JSVal+syncCallback3 = undefined+-----------------------------------------------------------------------------+-- | A synchronous callback that returns a value+syncCallback' :: IO JSVal -> IO JSVal+syncCallback' = undefined+-- | A synchronous callback that takes a single argument and returns a value+syncCallback1' :: (JSVal -> IO JSVal) -> IO JSVal+syncCallback1' = undefined+-- | A synchronous callback that takes two arguments and returns a value+syncCallback2' :: (JSVal -> JSVal -> IO JSVal) -> IO JSVal+syncCallback2' = undefined+-- | A synchronous callback that takes three arguments and returns a value+syncCallback3' :: (JSVal -> JSVal -> JSVal -> IO JSVal) -> IO JSVal+syncCallback3' = undefined+-----------------------------------------------------------------------------+parseInt :: Text -> Maybe Int+parseInt = readMaybe . unpack+-----------------------------------------------------------------------------+parseDouble :: Text -> Maybe Double+parseDouble = readMaybe . unpack+-----------------------------------------------------------------------------+parseWord :: Text -> Maybe Word+parseWord = readMaybe . unpack+-----------------------------------------------------------------------------+parseFloat :: Text -> Maybe Float+parseFloat = readMaybe . unpack+-----------------------------------------------------------------------------+toString_Int :: Int -> Text+toString_Int = pack . show+-----------------------------------------------------------------------------+toString_Word :: Word -> Text+toString_Word = pack . show+-----------------------------------------------------------------------------+toString_Float :: Float -> Text+toString_Float = pack . show+-----------------------------------------------------------------------------+toString_Double :: Double -> Text+toString_Double = pack . show+-----------------------------------------------------------------------------
+ ffi/js/Miso/DSL/FFI.hs view
@@ -0,0 +1,432 @@+-----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE LambdaCase #-}+-----------------------------------------------------------------------------+{-# OPTIONS_GHC -fno-warn-orphans #-}+-----------------------------------------------------------------------------+module Miso.DSL.FFI+ ( -- ** Types+ JSVal+ , JSString+ -- ** Serialization FFI+ -- *** ToJSVal+ , toJSVal_Char+ , toJSVal_Bool+ , toJSVal_Double+ , toJSVal_Float+ , toJSVal_Int+ , toJSVal_List+ , toJSVal_JSString+ , toJSVal_Text+ -- *** FromJSVal+ , fromJSVal_Text+ , fromJSValUnchecked_Text+ , fromJSVal_Char+ , fromJSValUnchecked_Char+ , fromJSVal_Bool+ , fromJSValUnchecked_Bool+ , fromJSVal_Double+ , fromJSValUnchecked_Double+ , fromJSVal_Float+ , fromJSValUnchecked_Float+ , fromJSVal_Int+ , fromJSValUnchecked_Int+ , fromJSVal_List+ , fromJSVal_JSString+ , fromJSVal_Maybe+ , fromJSValUnchecked_Maybe+ -- * Callback FFI+ , asyncCallback+ , asyncCallback1+ , asyncCallback2+ , asyncCallback3+ , syncCallback+ , syncCallback1+ , syncCallback2+ , syncCallback3+ , syncCallback'+ , syncCallback1'+ , syncCallback2'+ , syncCallback3'+ -- * DSL FFI+ , invokeFunction+ , setProp_ffi+ , new_ffi+ , getProp_ffi+ , eval_ffi+ , setPropIndex_ffi+ , getPropIndex_ffi+ , create_ffi+ -- *** Misc. FFI+ , global+ , isUndefined_ffi+ , isNull_ffi+ , jsNull+ , freeFunction_ffi+ , listProps_ffi+ , requestAnimationFrame+ , cancelAnimationFrame+ -- *** String FFI+ , parseInt+ , parseDouble+ , parseWord+ , parseFloat+ , toString_Double+ , toString_Float+ , toString_Word+ , toString_Int+ ) where+-----------------------------------------------------------------------------+import Data.JSString+import Data.Text+-----------------------------------------------------------------------------+import qualified GHCJS.Marshal as Marshal+import GHCJS.Types+#ifdef GHCJS_NEW+import GHC.JS.Prim+import qualified GHC.JS.Foreign.Callback as Callback+#elif GHCJS_OLD+import GHCJS.Prim+import qualified GHCJS.Foreign.Callback as Callback+#endif+-----------------------------------------------------------------------------+foreign import javascript safe+#ifdef GHCJS_NEW+ "(($1,$2) => { return $1 === $2; })"+#else+ "$r = $1 === $2;"+#endif+ eq :: JSVal -> JSVal -> Bool+-----------------------------------------------------------------------------+instance Eq JSVal where+ (==) = eq+ {-# INLINE (==) #-}+-----------------------------------------------------------------------------+toJSVal_Bool :: Bool -> IO JSVal+toJSVal_Bool = Marshal.toJSVal+{-# INLINE toJSVal_Bool #-}+-----------------------------------------------------------------------------+toJSVal_Double :: Double -> IO JSVal+toJSVal_Double = Marshal.toJSVal+{-# INLINE toJSVal_Double #-}+-----------------------------------------------------------------------------+toJSVal_Int :: Int -> IO JSVal+toJSVal_Int = Marshal.toJSVal+{-# INLINE toJSVal_Int #-}+-----------------------------------------------------------------------------+toJSVal_List :: [JSVal] -> IO JSVal+toJSVal_List = Marshal.toJSVal+{-# INLINE toJSVal_List #-}+-----------------------------------------------------------------------------+fromJSVal_Bool :: JSVal -> IO (Maybe Bool)+fromJSVal_Bool = Marshal.fromJSVal+{-# INLINE fromJSVal_Bool #-}+-----------------------------------------------------------------------------+foreign import javascript safe+#ifdef GHCJS_NEW+ "(($1,$2) => { return new $1(...$2) })"+#else+ "$r = Reflect.construct($1, $2);"+#endif+ new_ffi :: JSVal -> JSVal -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1) => { return eval($1); })"+#else+ "$r = eval($1);"+#endif+ eval_ffi :: JSString -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(() => { return {}; })"+#else+ "$r = {};"+#endif+ create_ffi :: IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1,$2) => { return $2[$1]; })"+#else+ "$r=$2[$1]"+#endif+ getProp_ffi :: JSString -> JSVal -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1,$2,$3) => { return $3[$1]=$2; })"+#else+ "$3[$1]=$2"+#endif+ setProp_ffi+ :: JSString+ -- ^ Key+ -> JSVal+ -- ^ Value+ -> JSVal+ -- ^ Object+ -> IO ()+-----------------------------------------------------------------------------+fromJSVal_Int :: JSVal -> IO (Maybe Int)+fromJSVal_Int = Marshal.fromJSVal+{-# INLINE fromJSVal_Int #-}+-----------------------------------------------------------------------------+fromJSVal_Double :: JSVal -> IO (Maybe Double)+fromJSVal_Double = Marshal.fromJSVal+{-# INLINE fromJSVal_Double #-}+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1,$2) => { return $2[$1]; })"+#else+ "$r=$2[$1]"+#endif+ getPropIndex_ffi :: Int -> JSVal -> IO JSVal+-----------------------------------------------------------------------------+isNull_ffi :: JSVal -> Bool+isNull_ffi = isNull+{-# INLINE isNull_ffi #-}+-----------------------------------------------------------------------------+isUndefined_ffi :: JSVal -> Bool+isUndefined_ffi = isUndefined+{-# INLINE isUndefined_ffi #-}+-----------------------------------------------------------------------------+freeFunction_ffi :: JSVal -> IO ()+freeFunction_ffi _ = pure ()+{-# INLINE freeFunction_ffi #-}+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1) => { return requestAnimationFrame($1); })"+#else+ "$r = requestAnimationFrame($1);"+#endif+ requestAnimationFrame :: JSVal -> IO Int+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1) => { return cancelAnimationFrame($1); })"+#else+ "cancelAnimationFrame($1);"+#endif+ cancelAnimationFrame :: Int -> IO ()+-----------------------------------------------------------------------------+toJSVal_JSString :: JSString -> IO JSVal+toJSVal_JSString = Marshal.toJSVal+{-# INLINE toJSVal_JSString #-}+-----------------------------------------------------------------------------+fromJSValUnchecked_Maybe :: JSVal -> IO (Maybe JSVal)+fromJSValUnchecked_Maybe = Marshal.fromJSValUnchecked+{-# INLINE fromJSValUnchecked_Maybe #-}+-----------------------------------------------------------------------------+fromJSVal_Maybe :: JSVal -> IO (Maybe (Maybe JSVal))+fromJSVal_Maybe = Marshal.fromJSVal+{-# INLINE fromJSVal_Maybe #-}+-----------------------------------------------------------------------------+fromJSValUnchecked_Bool :: JSVal -> IO Bool+fromJSValUnchecked_Bool = Marshal.fromJSValUnchecked+{-# INLINE fromJSValUnchecked_Bool #-}+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1,$2,$3) => { return $1.apply($2, $3); })"+#else+ "$r = $1.apply($2, $3);"+#endif+ invokeFunction :: JSVal -> JSVal -> JSVal -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1) => { return Object.keys($1); })"+#else+ "$r = Object.keys($1);"+#endif+ listProps_ffi :: JSVal -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1,$2,$3) => { return $3[$1]=$2; })"+#else+ "$3[$1]=$2"+#endif+ setPropIndex_ffi+ :: Int+ -- ^ Key+ -> JSVal+ -- ^ Value+ -> JSVal+ -- ^ Object+ -> IO ()+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(() => { return globalThis; })"+#else+ "$r = globalThis"+#endif+ global :: JSVal+-----------------------------------------------------------------------------+fromJSVal_List :: JSVal -> IO (Maybe [JSVal])+fromJSVal_List = Marshal.fromJSVal+{-# INLINE fromJSVal_List #-}+-----------------------------------------------------------------------------+fromJSValUnchecked_Int :: JSVal -> IO Int+fromJSValUnchecked_Int = Marshal.fromJSValUnchecked+{-# INLINE fromJSValUnchecked_Int #-}+-----------------------------------------------------------------------------+fromJSValUnchecked_Double :: JSVal -> IO Double+fromJSValUnchecked_Double = Marshal.fromJSValUnchecked+{-# INLINE fromJSValUnchecked_Double #-}+-----------------------------------------------------------------------------+fromJSVal_JSString :: JSVal -> IO (Maybe JSString)+fromJSVal_JSString = Marshal.fromJSVal+{-# INLINE fromJSVal_JSString #-}+-----------------------------------------------------------------------------+toJSVal_Char :: Char -> IO JSVal+toJSVal_Char = Marshal.toJSVal+{-# INLINE toJSVal_Char #-}+-----------------------------------------------------------------------------+toJSVal_Float :: Float -> IO JSVal+toJSVal_Float = Marshal.toJSVal+{-# INLINE toJSVal_Float #-}+-----------------------------------------------------------------------------+toJSVal_Text :: Text -> IO JSVal+toJSVal_Text = Marshal.toJSVal+{-# INLINE toJSVal_Text #-}+-----------------------------------------------------------------------------+fromJSVal_Text :: JSVal -> IO (Maybe Text)+fromJSVal_Text = Marshal.fromJSVal+{-# INLINE fromJSVal_Text #-}+-----------------------------------------------------------------------------+fromJSValUnchecked_Text :: JSVal -> IO Text+fromJSValUnchecked_Text = Marshal.fromJSValUnchecked+{-# INLINE fromJSValUnchecked_Text #-}+-----------------------------------------------------------------------------+fromJSVal_Char :: JSVal -> IO (Maybe Char)+fromJSVal_Char = Marshal.fromJSVal+{-# INLINE fromJSVal_Char #-}+-----------------------------------------------------------------------------+fromJSValUnchecked_Char :: JSVal -> IO Char+fromJSValUnchecked_Char = Marshal.fromJSValUnchecked+{-# INLINE fromJSValUnchecked_Char #-}+-----------------------------------------------------------------------------+fromJSVal_Float :: JSVal -> IO (Maybe Float)+fromJSVal_Float = Marshal.fromJSVal+{-# INLINE fromJSVal_Float #-}+-----------------------------------------------------------------------------+fromJSValUnchecked_Float :: JSVal -> IO Float+fromJSValUnchecked_Float = Marshal.fromJSValUnchecked+{-# INLINE fromJSValUnchecked_Float #-}+-----------------------------------------------------------------------------+asyncCallback :: IO () -> IO JSVal+asyncCallback x = jsval <$> Callback.asyncCallback x+{-# INLINE asyncCallback #-}+asyncCallback1 :: (JSVal -> IO ()) -> IO JSVal+asyncCallback1 x = jsval <$> Callback.asyncCallback1 x+{-# INLINE asyncCallback1 #-}+asyncCallback2 :: (JSVal -> JSVal -> IO ()) -> IO JSVal+asyncCallback2 x = jsval <$> Callback.asyncCallback2 x+{-# INLINE asyncCallback2 #-}+asyncCallback3 :: (JSVal -> JSVal -> JSVal -> IO ()) -> IO JSVal+asyncCallback3 x = jsval <$> Callback.asyncCallback3 x+{-# INLINE asyncCallback3 #-}+-----------------------------------------------------------------------------+syncCallback :: IO () -> IO JSVal+syncCallback x = jsval <$> Callback.syncCallback Callback.ThrowWouldBlock x+{-# INLINE syncCallback #-}+syncCallback1 :: (JSVal -> IO ()) -> IO JSVal+syncCallback1 x = jsval <$> Callback.syncCallback1 Callback.ThrowWouldBlock x+{-# INLINE syncCallback1 #-}+syncCallback2 :: (JSVal -> JSVal -> IO ()) -> IO JSVal+syncCallback2 x = jsval <$> Callback.syncCallback2 Callback.ThrowWouldBlock x+{-# INLINE syncCallback2 #-}+syncCallback3 :: (JSVal -> JSVal -> JSVal -> IO ()) -> IO JSVal+syncCallback3 x = jsval <$> Callback.syncCallback3 Callback.ThrowWouldBlock x+{-# INLINE syncCallback3 #-}+-----------------------------------------------------------------------------+syncCallback' :: IO JSVal -> IO JSVal+syncCallback' x = jsval <$> Callback.syncCallback' x+{-# INLINE syncCallback' #-}+syncCallback1' :: (JSVal -> IO JSVal) -> IO JSVal+syncCallback1' x = jsval <$> Callback.syncCallback1' x+{-# INLINE syncCallback1' #-}+syncCallback2' :: (JSVal -> JSVal -> IO JSVal) -> IO JSVal+syncCallback2' x = jsval <$> Callback.syncCallback2' x+{-# INLINE syncCallback2' #-}+syncCallback3' :: (JSVal -> JSVal -> JSVal -> IO JSVal) -> IO JSVal+syncCallback3' x = jsval <$> Callback.syncCallback3' x+{-# INLINE syncCallback3' #-}+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1) => { return parseInt($1); })"+#else+ "$r = parseInt($1)"+#endif+ parseInt_Unchecked :: JSString -> Double+-----------------------------------------------------------------------------+parseWord :: JSString -> Maybe Word+parseWord string = fromIntegral <$> parseInt string+{-# INLINE parseWord #-}+-----------------------------------------------------------------------------+parseInt :: JSString -> Maybe Int+parseInt string =+ case parseInt_Unchecked string of+ double | isNaN double -> Nothing+ | otherwise -> Just (round double)+{-# INLINE parseInt #-}+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1) => { return parseFloat($1); })"+#else+ "$r = parseFloat($1)"+#endif+ parseDouble_Unchecked :: JSString -> Double+-----------------------------------------------------------------------------+parseDouble :: JSString -> Maybe Double+parseDouble string =+ case parseDouble_Unchecked string of+ double | isNaN double -> Nothing+ | otherwise -> Just double+{-# INLINE parseDouble #-}+-----------------------------------------------------------------------------+parseFloat :: JSString -> Maybe Float+parseFloat string = realToFrac <$> parseDouble string+{-# INLINE parseFloat #-}+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1) => { return ($1).toString(); })"+#else+ "$r = String($1);"+#endif+ toString_Int :: Int -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1) => { return ($1).toString(); })"+#else+ "$r = String($1);"+#endif+ toString_Double :: Double -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1) => { return ($1).toString(); })"+#else+ "$r = String($1);"+#endif+ toString_Float :: Float -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+#if GHCJS_NEW+ "(($1) => { return ($1).toString(); })"+#else+ "$r = String($1);"+#endif+ toString_Word :: Word -> JSString+-----------------------------------------------------------------------------
+ ffi/wasm/Data/JSString.hs view
@@ -0,0 +1,920 @@+-----------------------------------------------------------------------------+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE MultilineStrings #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MagicHash #-}+-----------------------------------------------------------------------------+{-# OPTIONS_GHC -fno-warn-orphans #-}+-----------------------------------------------------------------------------+module Data.JSString+ ( -- * Types+ JSString (..)+ -- * Creation and elimination+ , pack+ , unpack+ , singleton+ , empty+ -- * Basic interface+ , cons+ , snoc+ , append+ , uncons+ , unsnoc+ , head+ , last+ , tail+ , init+ , null+ , length+ , compareLength+ -- * Transformations+ , map+ , intercalate+ , intersperse+ , transpose+ , reverse+ , replace+ -- ** Case conversion+ , toCaseFold+ , toLower+ , toUpper+ , toTitle+ -- ** Justification+ , justifyLeft+ , justifyRight+ , center+ -- * Folds+ , foldl+ , foldl'+ , foldl1+ , foldr+ , foldr1+ -- ** Special folds+ , concat+ , concatMap+ , any+ , all+ , maximum+ , minimum+ -- * Construction+ -- ** Scans+ , scanl+ , scanl1+ , scanr+ , scanr1+ -- ** Accumulating maps+ , mapAccumL+ , mapAccumR+ -- ** Generation and unfolding+ , replicate+ , unfoldr+ , unfoldrN+ -- * Substrings+ -- ** Breaking strings+ , take+ , takeEnd+ , drop+ , dropEnd+ , takeWhile+ , takeWhileEnd+ , dropWhile+ , dropWhileEnd+ , dropAround+ , strip+ , stripStart+ , stripEnd+ , splitAt+ , breakOn+ , breakOnEnd+ , break+ , span+ , group+ , groupBy+ , inits+ , tails+ -- ** Breaking into many substrings+ , splitOn+ , split+ , chunksOf+ -- ** Breaking into lines and words+ , lines+ , words+ , unlines+ , unwords+ -- * Predicates+ , isPrefixOf+ , isSuffixOf+ , isInfixOf+ -- ** View patterns+ , stripPrefix+ , stripSuffix+ , commonPrefixes+ -- * Searching+ , filter+ -- , breakOnAll+ , find+ , partition+ -- * Indexing+ , index+ , findIndex+ , count+ -- * Zipping+ , zip+ , zipWith+ -- * Misc+ , textFromJSString+ , textToJSString+ , toJSString+ , fromJSString+ , toString_Double+ , toString_Float+ , toString_Word+ , toString_Int+ ) where+-----------------------------------------------------------------------------+import Data.Array.Byte (ByteArray(..))+import Data.Text.Internal hiding (pack, empty, append)+import GHC.Exts+import GHC.IO+import GHC.Wasm.Prim+import qualified Data.List as List+import qualified Data.Text as T+import Prelude+ hiding ( length, head, tail, filter, zip+ , zipWith, unlines, unwords, null+ , map, reverse, foldl', last, init+ , foldl, foldl1, foldr, foldr1, concat+ , concatMap, any, maximum, all, minimum+ , scanl, scanl1, scanr, scanr1, replicate+ , take, drop, takeWhile, dropWhile, splitAt+ , break, span, lines, words+ )+-----------------------------------------------------------------------------+pack :: String -> JSString+{-# INLINE pack #-}+pack = toJSString+-----------------------------------------------------------------------------+empty :: JSString+{-# INLINE empty #-}+empty = mempty+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return String.fromCharCode($1) + $2;+ """ cons :: Char -> JSString -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1 + String.fromCharCode($2);+ """ snoc :: JSString -> Char -> JSString+-----------------------------------------------------------------------------+append :: JSString -> JSString -> JSString+{-# INLINE append #-}+append = mappend+-----------------------------------------------------------------------------+unsnoc :: JSString -> Maybe (JSString, Char) +{-# INLINE unsnoc #-}+unsnoc s+ | 0 <- length s = Nothing+ | otherwise = Just (init s, last s)+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1.length === 0) throw new Error ('last: empty string');+ return $1.slice(-1).charCodeAt();+ """ last :: JSString -> Char+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1.length === 0) throw new Error ('init: empty string');+ return $1.slice(0,-1);+ """ init :: JSString -> JSString+-----------------------------------------------------------------------------+compareLength :: JSString -> Int -> Ordering+{-# INLINE compareLength #-}+compareLength str = compare (length str)+-----------------------------------------------------------------------------+map :: (Char -> Char) -> JSString -> JSString+{-# INLINE map #-}+map f s =+ case uncons s of+ Nothing -> mempty+ Just (c, next) ->+ f c `cons` map f next+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ const sep = String.fromCharCode($1)+ if ($2.length === 0) return '';+ else if ($2.length === 1) return $2;+ else return $2.split('').join(sep);+ """ intersperse :: Char -> JSString -> JSString+-----------------------------------------------------------------------------+transpose :: [JSString] -> [JSString]+{-# INLINE transpose #-}+transpose = fmap toJSString . List.transpose . fmap fromJSString+-----------------------------------------------------------------------------+-- | Reverses a t'Miso.String.MisoString'+--+-- @+-- reverse "abc"+-- "cba"+-- @+foreign import javascript unsafe+ """+ return [...$1].reverse().join('');+ """ reverse :: JSString -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $3.replace($1,$2);+ """ replace :: JSString -> JSString -> JSString -> JSString+-----------------------------------------------------------------------------+toCaseFold :: JSString -> JSString+{-# INLINE toCaseFold #-}+toCaseFold = textToJSString . T.toCaseFold . textFromJSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1.toLowerCase();+ """ toLower :: JSString -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1.toUpperCase();+ """ toUpper :: JSString -> JSString+-----------------------------------------------------------------------------+toTitle :: JSString -> JSString+{-# INLINE toTitle #-}+toTitle = textToJSString . T.toTitle . textFromJSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1 <= $3.length) return $3;+ let paddings = $1 - $3.length;+ while (paddings > 0) {+ $3 += String.fromCharCode($2);+ paddings--;+ }+ return $3;+ """ justifyLeft :: Int -> Char -> JSString -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1 <= $3.length) return $3;+ let paddings = $1 - $3.length;+ while (paddings > 0) {+ $3 = String.fromCharCode($2) + $3;+ paddings--;+ }+ return $3;+ """ justifyRight :: Int -> Char -> JSString -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1 <= $3.length) return $3;+ let paddings = ($1 - $3.length) / 2;+ let left = Math.ceil(paddings);+ let right = Math.floor(paddings);+ while (left > 0) {+ $3 = String.fromCharCode($2) + $3;+ left--;+ }+ while (right > 0) {+ $3 += String.fromCharCode($2);+ right--;+ }+ return $3;+ """ center :: Int -> Char -> JSString -> JSString+-----------------------------------------------------------------------------+foldl :: (a -> Char -> a) -> a -> JSString -> a+{-# INLINE foldl #-}+foldl f x ys =+ case uncons ys of+ Nothing -> x+ Just (c, next) -> foldl f (f x c) next+-----------------------------------------------------------------------------+foldl1 :: (Char -> Char -> Char) -> JSString -> Char+{-# INLINE foldl1 #-}+foldl1 f xs =+ case uncons xs of+ Nothing -> error "foldl1: empty string"+ Just (c,next) ->+ foldl f c next+-----------------------------------------------------------------------------+foldr :: (Char -> a -> a) -> a -> JSString -> a+{-# INLINE foldr #-}+foldr f x ys =+ case uncons ys of+ Nothing -> x+ Just (c, next) ->+ f c (foldr f x next)+-----------------------------------------------------------------------------+foldr1 :: (Char -> Char -> Char) -> JSString -> Char+{-# INLINE foldr1 #-}+foldr1 f ys =+ case uncons ys of+ Nothing -> error "foldr1: empty string"+ Just (c, next)+ | length next == 0 -> c+ | otherwise -> f c (foldr1 f next)+-----------------------------------------------------------------------------+any :: (Char -> Bool) -> JSString -> Bool+{-# INLINE any #-}+any f str =+ case uncons str of+ Nothing -> False+ Just (c, next) ->+ f c || any f next+-----------------------------------------------------------------------------+all :: (Char -> Bool) -> JSString -> Bool+{-# INLINE all #-}+all f str =+ case uncons str of+ Nothing -> True+ Just (c, next) ->+ f c && all f next+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1.length === 0) throw new Error ('maximum: empty string');++ let max = $1[0].charCodeAt();+ for (let i = 0; i < $1.length; i++) {+ if (max < $1[i].charCodeAt()) {+ max = $1[i].charCodeAt();+ }+ }+ return max;+ """ maximum :: JSString -> Char+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1.length === 0) throw new Error ('minimum: empty string');++ let min = $1[0].charCodeAt();+ for (let i = 0; i < $1.length; i++) {+ if ($1[i].charCodeAt() < min) {+ min = $1[i].charCodeAt();+ }+ }+ return min;+ """ minimum :: JSString -> Char+-----------------------------------------------------------------------------+scanl :: (Char -> Char -> Char) -> Char -> JSString -> JSString+{-# INLINE scanl #-}+scanl f x ys =+ case uncons ys of+ Nothing -> singleton x+ Just (c, next) ->+ x `cons` scanl f (f x c) next+-----------------------------------------------------------------------------+scanl1 :: (Char -> Char -> Char) -> JSString -> JSString+{-# INLINE scanl1 #-}+scanl1 f ys =+ case uncons ys of+ Nothing -> mempty+ Just (c, next) ->+ scanl f c next +-----------------------------------------------------------------------------+scanr :: (Char -> Char -> Char) -> Char -> JSString -> JSString+{-# INLINE scanr #-}+scanr f q0 ys = + case uncons ys of+ Nothing -> singleton q0+ Just (x, xs) ->+ case uncons (scanr f q0 xs) of+ Just (q, qss) -> do+ let qs = q `cons` qss+ f x q `cons` qs+ Nothing -> error "scanr: impossible" +-----------------------------------------------------------------------------+scanr1 :: (Char -> Char -> Char) -> JSString -> JSString+{-# INLINE scanr1 #-}+scanr1 f ys = + case uncons ys of+ Nothing -> mempty+ Just (x, xs)+ | length xs == 0 -> singleton x+ | otherwise -> do+ case uncons (scanr1 f xs) of+ Just (q, qss) -> f x q `cons` (q `cons` qss)+ Nothing -> error "scanr: impossible" +-----------------------------------------------------------------------------+mapAccumL :: (a -> Char -> (a, Char)) -> a -> JSString -> (a, JSString)+{-# INLINE mapAccumL #-}+mapAccumL f x str =+ case uncons str of+ Nothing -> (x, str)+ Just (c, next) -> do+ let (a, c') = f x c+ cons c' <$> mapAccumL f a next+-----------------------------------------------------------------------------+mapAccumR :: (a -> Char -> (a, Char)) -> a -> JSString -> (a, JSString)+{-# INLINE mapAccumR #-}+mapAccumR f x str =+ case uncons str of+ Nothing -> (x, str)+ Just (c, next) ->+ case mapAccumR f x next of+ (a, qs) ->+ case f a c of+ (a', k) -> (a', k `cons` qs)+-----------------------------------------------------------------------------+unfoldr :: (a -> Maybe (Char, a)) -> a -> JSString+{-# INLINE unfoldr #-}+unfoldr f x = do+ case f x of+ Nothing -> mempty+ Just (c, y) ->+ c `cons` unfoldr f y+-----------------------------------------------------------------------------+unfoldrN :: Int -> (a -> Maybe (Char, a)) -> a -> JSString+{-# INLINE unfoldrN #-}+unfoldrN n f seed = go seed mempty+ where+ go x acc+ | length acc == n = acc+ | otherwise =+ case f x of+ Nothing -> mempty+ Just (c,y) -> go y (c `cons` acc)+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1 < 1) return "";+ return $2.slice(0, $1);+ """ take :: Int -> JSString -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1 < 1) return "";+ return $2.slice(-$1);+ """ takeEnd :: Int -> JSString -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1 < 1) return "";+ return $2.slice(0, -$1);+ """ dropEnd :: Int -> JSString -> JSString+-----------------------------------------------------------------------------+takeWhile :: (Char -> Bool) -> JSString -> JSString+{-# INLINE takeWhile #-}+takeWhile f xs =+ case uncons xs of+ Nothing -> mempty+ Just (c, next) ->+ if f c+ then c `cons` takeWhile f next+ else mempty+-----------------------------------------------------------------------------+takeWhileEnd :: (Char -> Bool) -> JSString -> JSString+{-# INLINE takeWhileEnd #-}+takeWhileEnd f = reverse . takeWhile f . reverse+-----------------------------------------------------------------------------+dropWhile :: (Char -> Bool) -> JSString -> JSString+{-# INLINE dropWhile #-}+dropWhile f xs =+ case uncons xs of+ Nothing -> xs+ Just (c, next) ->+ if f c+ then dropWhile f next+ else xs+-----------------------------------------------------------------------------+dropWhileEnd :: (Char -> Bool) -> JSString -> JSString+{-# INLINE dropWhileEnd #-}+dropWhileEnd f = reverse . dropWhile f . reverse+-----------------------------------------------------------------------------+dropAround :: (Char -> Bool) -> JSString -> JSString+{-# INLINE dropAround #-}+dropAround f = dropWhile f . dropWhileEnd f+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1.trim();+ """ strip :: JSString -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1.trimStart();+ """ stripStart :: JSString -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1.trimEnd();+ """ stripEnd :: JSString -> JSString+-----------------------------------------------------------------------------+splitAt :: Int -> JSString -> (JSString, JSString)+{-# INLINE splitAt #-}+splitAt n xs = (take n xs, drop n xs)+-----------------------------------------------------------------------------+breakOn :: JSString -> JSString -> (JSString, JSString)+{-# INLINE breakOn #-}+breakOn n _ | 0 <- length n = error "breakOn: empty needle"+breakOn needle haystack = go (mempty, haystack)+ where+ go (acc, stack) =+ if needle `isPrefixOf` stack+ then (acc, stack)+ else+ case uncons stack of+ Nothing -> (acc, stack)+ Just (c,next) ->+ go (acc `snoc` c, next)+-----------------------------------------------------------------------------+breakOnEnd :: JSString -> JSString -> (JSString, JSString)+{-# INLINE breakOnEnd #-}+breakOnEnd n _ | 0 <- length n = error "breakOnEnd: empty needle"+breakOnEnd needle haystack = go (mempty, haystack)+ where+ go (acc, stack) =+ if needle `isSuffixOf` stack+ then (stack, acc)+ else+ case unsnoc stack of+ Nothing -> (stack, acc)+ Just (next, c) ->+ go (c `cons` acc, next)+-----------------------------------------------------------------------------+break :: (Char -> Bool) -> JSString -> (JSString, JSString)+{-# INLINE break #-}+break f s = go (mempty, s)+ where+ go (failed, rest) =+ case uncons rest of+ Nothing -> (failed, rest)+ Just (c,next) ->+ if f c+ then (failed, c `cons` next)+ else go (failed `snoc` c, next)+-----------------------------------------------------------------------------+span :: (Char -> Bool) -> JSString -> (JSString, JSString)+{-# INLINE span #-}+span f s = (takeWhile f s, dropWhile f s)+-----------------------------------------------------------------------------+group :: JSString -> [JSString]+{-# INLINE group #-}+group = groupBy (==)+-----------------------------------------------------------------------------+groupBy :: (Char -> Char -> Bool) -> JSString -> [JSString]+{-# INLINE groupBy #-}+groupBy eq s' =+ case uncons s' of+ Nothing -> []+ Just (c, next) -> do+ let (ys, zs) = span (eq c) next+ (c `cons` ys) : groupBy eq zs+-----------------------------------------------------------------------------+inits :: JSString -> [JSString]+{-# INLINE inits #-}+inits s = + case unsnoc s of+ Nothing -> [""]+ Just (next, _) -> inits next <> [s]+-----------------------------------------------------------------------------+tails :: JSString -> [JSString]+{-# INLINE tails #-}+tails s =+ case uncons s of+ Nothing -> [""]+ Just (_, next) -> s : tails next+-----------------------------------------------------------------------------+splitOn :: JSString -> JSString -> [JSString]+{-# INLINE splitOn #-}+splitOn prefix _ | 0 <- length prefix = error "splitOn: empty prefix"+splitOn prefix str = go str mempty+ where+ go s acc | 0 <- length s = [acc]+ go s acc = do+ if prefix `isPrefixOf` s+ then acc : go (drop (length prefix) s) mempty+ else+ case uncons s of+ Nothing -> [acc]+ Just (c,next) ->+ go next (acc `snoc` c)+-----------------------------------------------------------------------------+split :: (Char -> Bool) -> JSString -> [JSString]+{-# INLINE split #-}+split f = go+ where+ go str | 0 <- length str = [empty]+ go str = do+ let+ found = takeWhile (not . f) str+ next = drop 1 (dropWhile (not . f) str)+ found : go next+-----------------------------------------------------------------------------+chunksOf :: Int -> JSString -> [JSString]+{-# INLINE chunksOf #-}+chunksOf 0 _ = []+chunksOf n s =+ case (take n s, drop n s) of+ (hd, tl) ->+ if length tl == 0+ then [hd]+ else hd : chunksOf n tl+-----------------------------------------------------------------------------+lines :: JSString -> [JSString]+{-# INLINE lines #-}+lines = splitOn "\n"+-----------------------------------------------------------------------------+words :: JSString -> [JSString]+{-# INLINE words #-}+words s = go (strip s)+ where+ go xs | length xs == 0 = []+ go xs = do+ let next = dropWhile (==' ') xs+ let payload = takeWhile (/=' ') next+ payload : go (drop (length payload) next)+-----------------------------------------------------------------------------+unwords :: [JSString] -> JSString+{-# INLINE unwords #-}+unwords = intercalate " "+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $2.endsWith($1);+ """ isSuffixOf :: JSString -> JSString -> Bool+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $2.includes($1);+ """ isInfixOf :: JSString -> JSString -> Bool+-----------------------------------------------------------------------------+stripPrefix :: JSString -> JSString -> Maybe JSString+{-# INLINE stripPrefix #-}+stripPrefix prefix string+ | not (prefix `isPrefixOf` string) = Nothing+ | otherwise = Just (drop (length prefix) string)+-----------------------------------------------------------------------------+stripSuffix :: JSString -> JSString -> Maybe JSString+{-# INLINE stripSuffix #-}+stripSuffix suffix string+ | not (suffix `isSuffixOf` string) = Nothing+ | otherwise = Just (dropEnd (length suffix) string)+-----------------------------------------------------------------------------+commonPrefixes :: JSString -> JSString -> Maybe (JSString, JSString, JSString)+{-# INLINE commonPrefixes #-}+commonPrefixes ls rs | length ls == 0 || length rs == 0 = Nothing+commonPrefixes ls' rs' = go mempty ls' rs'+ where+ go acc ls rs =+ case (uncons ls, uncons rs) of+ (Just (l,lss), Just (r,rss)) ->+ if l == r+ then go (acc `snoc` l) lss rss+ else+ if null acc+ then Nothing+ else Just (acc, l `cons` lss, r `cons` rss)+ _ -> Nothing+-----------------------------------------------------------------------------+filter :: (Char -> Bool) -> JSString -> JSString+{-# INLINE filter #-}+filter f xs =+ case uncons xs of+ Nothing -> mempty+ Just (c,next) ->+ if f c+ then c `cons` filter f next+ else filter f next+-----------------------------------------------------------------------------+-- breakOnAll :: JSString -> JSString -> [(JSString, JSString)]+-- breakOnAll = error "TODO: implement breakOnAll"+-----------------------------------------------------------------------------+find :: (Char -> Bool) -> JSString -> Maybe Char+{-# INLINE find #-}+find f xs = do+ (c,next) <- uncons xs+ if f c+ then pure c+ else find f next+-----------------------------------------------------------------------------+partition :: (Char -> Bool) -> JSString -> (JSString, JSString)+{-# INLINE partition #-}+partition f xs = (filter f xs, filter (not . f) xs)+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1.length === 0) throw new Error ('index: empty string')+ return $1[$2].charCodeAt();+ """ index :: JSString -> Int -> Char+-----------------------------------------------------------------------------+findIndex :: (Char -> Bool) -> JSString -> Maybe Int+findIndex f xs = go xs+ where+ len = length xs - 1+ go zs = do+ (next, ys) <- uncons zs+ if f next+ then pure (len - length ys)+ else go ys+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1.length === 0) throw new Error ('count: empty string')+ return $2.split($1).length - 1;+ """ count :: JSString -> JSString -> Int+-----------------------------------------------------------------------------+zip :: JSString -> JSString -> [(Char,Char)]+{-# INLINE zip #-}+zip l r =+ case (uncons l, uncons r) of+ (Just (l',ls), Just (r',rs)) ->+ (l',r') : zip ls rs+ _ -> []+-----------------------------------------------------------------------------+zipWith :: (Char -> Char -> Char) -> JSString -> JSString -> JSString+{-# INLINE zipWith #-}+zipWith f l r =+ case (uncons l, uncons r) of+ (Just (l', ls), Just (r', rs)) ->+ f l' r' `cons` zipWith f ls rs+ _ -> mempty+-----------------------------------------------------------------------------+newtype JSUint8Array = JSUint8Array JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe "(new TextEncoder()).encode($1)"+ js_str_encode :: JSString -> IO JSUint8Array+-----------------------------------------------------------------------------+foreign import javascript unsafe "$1.byteLength"+ js_buf_len :: JSUint8Array -> IO Int+-----------------------------------------------------------------------------+foreign import javascript unsafe "(new Uint8Array(__exports.memory.buffer, $2, $1.byteLength)).set($1)"+ js_from_buf :: JSUint8Array -> Ptr a -> IO ()+-----------------------------------------------------------------------------+foreign import javascript unsafe "(new TextDecoder('utf-8', {fatal: true})).decode(new Uint8Array(__exports.memory.buffer, $1, $2))"+ js_to_str :: Ptr a -> Int -> IO JSString+-----------------------------------------------------------------------------+textFromJSString :: JSString -> Text+{-# INLINE textFromJSString #-}+textFromJSString str = unsafeDupablePerformIO $ do+ buf <- js_str_encode str+ I# len# <- js_buf_len buf+ IO $ \s0 -> case newByteArray# len# s0 of+ (# s1, mba# #) -> case unIO (js_from_buf buf (Ptr (mutableByteArrayContents# mba#))) s1 of+ (# s2, _ #) -> case unIO (freeJSVal (coerce buf)) s2 of+ (# s3, _ #) -> case unsafeFreezeByteArray# mba# s3 of+ (# s4, ba# #) -> (# s4, Text (ByteArray ba#) 0 (I# len#) #)+-----------------------------------------------------------------------------+textToJSString :: Text -> JSString+{-# INLINE textToJSString #-}+textToJSString (Text (ByteArray ba#) (I# off#) (I# len#)) = unsafeDupablePerformIO $+ IO $ \s0 -> case newPinnedByteArray# len# s0 of+ (# s1, mba# #) -> case copyByteArray# ba# off# mba# 0# len# s1 of+ s2 -> keepAlive# mba# s2 $ unIO $ js_to_str (Ptr (mutableByteArrayContents# mba#)) $ I# len#+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1.length === 0+ """ null :: JSString -> Bool+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1 < 1 || $2.length === 0) return $2;+ return $2.slice($1, $2.length);+ """ drop :: Int -> JSString -> JSString+-----------------------------------------------------------------------------+foldl' :: (a -> Char -> a) -> a -> JSString -> a+{-# INLINE foldl' #-}+foldl' f x ys =+ case uncons ys of+ Nothing -> x+ Just (c, next) -> do+ let !z = f x c+ foldl' f z next+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1.length+ """ length :: JSString -> Int+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $2.startsWith($1)+ """ isPrefixOf :: JSString -> JSString -> Bool+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return String.fromCharCode($1);+ """ singleton :: Char -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1.length === 0) throw new Error ('head: empty string');+ return $1.slice(0).charCodeAt();+ """ head :: JSString -> Char+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1.slice(1,$1.length)+ """ tail :: JSString -> JSString+-----------------------------------------------------------------------------+uncons :: JSString -> Maybe (Char, JSString)+{-# INLINE uncons #-}+uncons str+ | 0 <- length str = Nothing+ | otherwise = Just (head str, tail str)+-----------------------------------------------------------------------------+unpack :: JSString -> String+{-# INLINE unpack #-}+unpack = fromJSString+-----------------------------------------------------------------------------+intercalate :: JSString -> [JSString] -> JSString+{-# INLINE intercalate #-}+intercalate sep = \case+ [] -> mempty+ [x] -> x+ (x:xs) -> x <> sep <> intercalate sep xs+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1 === $2) return 0;+ else if ($1 > $2) return 1;+ else return -1;+ """ jsstringOrd :: JSString -> JSString -> Int+-----------------------------------------------------------------------------+concat :: [JSString] -> JSString+{-# INLINE concat #-}+concat = mconcat+-----------------------------------------------------------------------------+concatMap :: (Char -> JSString) -> JSString -> JSString+{-# INLINE concatMap #-}+concatMap f str =+ case uncons str of+ Nothing -> mempty+ Just (c, next) -> f c <> concatMap f next+-----------------------------------------------------------------------------+unlines :: [JSString] -> JSString+{-# INLINE unlines #-}+unlines ks = concat [ snoc k '\n' | k <- ks ]+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1 < 1) { return ''; }+ else if ($1 === 1) { return $2; }+ else {+ const inc = $2;+ while (--$1) {+ $2 += inc;+ }+ return $2;+ }+ """ replicate :: Int -> JSString -> JSString+----------------------------------------------------------------------------+instance Ord JSString where+ compare s1 s2 =+ case jsstringOrd s1 s2 of+ 0 -> EQ+ 1 -> GT+ (-1) -> LT+ _ -> error "jsstringOrd: impossible"+ {-# INLINE compare #-}+----------------------------------------------------------------------------+instance Eq JSString where+ (==) = jsstringEq+ {-# INLINE (==) #-}+----------------------------------------------------------------------------+instance Semigroup JSString where+ (<>) = jsstringMappend+ {-# INLINE (<>) #-}+----------------------------------------------------------------------------+instance Monoid JSString where+ mempty = jsstringMempty+ {-# INLINE mempty #-}+----------------------------------------------------------------------------+instance Show JSString where+ show = show . fromJSString+ {-# INLINE show #-}+----------------------------------------------------------------------------+instance IsString JSString where+ fromString = toJSString+ {-# INLINE fromString #-}+-----------------------------------------------------------------------------+foreign import javascript unsafe "return $1 === $2"+ jsstringEq :: JSString -> JSString -> Bool+-----------------------------------------------------------------------------+foreign import javascript unsafe "return $1 + $2"+ jsstringMappend :: JSString -> JSString -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe "return ''"+ jsstringMempty :: JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe "return ($1).toString()"+ toString_Int :: Int -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe "return ($1).toString()"+ toString_Double :: Double -> JSString+-----------------------------------------------------------------------------+foreign import javascript unsafe "return ($1).toString()"+ toString_Float :: Float -> JSString+-----------------------------------------------------------------------------+toString_Word :: Word -> JSString+{-# INLINE toString_Word #-}+toString_Word = toJSString . show+-----------------------------------------------------------------------------
+ ffi/wasm/Miso/DSL/FFI.hs view
@@ -0,0 +1,480 @@+-----------------------------------------------------------------------------+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE MultilineStrings #-}+{-# LANGUAGE ForeignFunctionInterface #-}+-----------------------------------------------------------------------------+{-# OPTIONS_GHC -fno-warn-orphans #-}+-----------------------------------------------------------------------------+module Miso.DSL.FFI+ ( -- ** Types+ JSVal+ , JSString (..)+ -- ** Serialization FFI+ -- *** ToJSVal+ , toJSVal_Char+ , toJSVal_Bool+ , toJSVal_Double+ , toJSVal_Float+ , toJSVal_Int+ , toJSVal_List+ , toJSVal_JSString+ , toJSVal_Text+ -- *** FromJSVal+ , fromJSVal_Text+ , fromJSValUnchecked_Text+ , fromJSVal_Char+ , fromJSValUnchecked_Char+ , fromJSVal_Bool+ , fromJSValUnchecked_Bool+ , fromJSVal_Double+ , fromJSValUnchecked_Double+ , fromJSVal_Float+ , fromJSValUnchecked_Float+ , fromJSVal_Int+ , fromJSValUnchecked_Int+ , fromJSVal_List+ , fromJSValUnchecked_List+ , fromJSVal_JSString+ , fromJSVal_Maybe+ , fromJSValUnchecked_Maybe+ -- * Callback FFI+ , asyncCallback+ , asyncCallback1+ , asyncCallback2+ , asyncCallback3+ , syncCallback+ , syncCallback1+ , syncCallback2+ , syncCallback3+ , syncCallback'+ , syncCallback1'+ , syncCallback2'+ , syncCallback3'+ -- * DSL FFI+ , invokeFunction+ , setProp_ffi+ , new_ffi+ , getProp_ffi+ , eval_ffi+ , setPropIndex_ffi+ , getPropIndex_ffi+ , create_ffi+ -- *** Misc. FFI+ , global+ , isUndefined_ffi+ , isNull_ffi+ , jsNull+ , freeFunction_ffi+ , requestAnimationFrame+ , cancelAnimationFrame+ , listProps_ffi+ -- *** String FFI+ , parseInt+ , parseDouble+ , parseWord+ , parseFloat+ ) where+-----------------------------------------------------------------------------+import Data.Text (Text)+import Control.Monad+import Data.JSString (textFromJSString, textToJSString)+import Prelude hiding (length, head, tail, unlines, concat, null, drop, replicate, concatMap)+-----------------------------------------------------------------------------+import GHC.Wasm.Prim+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1 === $2;+ """ eq :: JSVal -> JSVal -> Bool+-----------------------------------------------------------------------------+instance Eq JSVal where+ (==) = eq+ {-# INLINE (==) #-}+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ if ($1 === 0.0) return false;+ return true;+ """ toJSVal_Bool :: Bool -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1+ """ toJSVal_Double :: Double -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1+ """ toJSVal_Int :: Int -> IO JSVal+-----------------------------------------------------------------------------+toJSVal_List :: [JSVal] -> IO JSVal+toJSVal_List js = do+ arr <- newArray+ forM_ js (pushArray arr)+ pure arr+{-# INLINE toJSVal_List #-}+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return [];+ """ newArray :: IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ $1.push($2)+ """ pushArray :: JSVal -> JSVal -> IO ()+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1+ """+ toJSVal_Char :: Char -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1+ """+ toJSVal_Float :: Float -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1+ """ fromJSValUnchecked_Float :: JSVal -> IO Float+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1+ """ fromJSValUnchecked_Char :: JSVal -> IO Char+-----------------------------------------------------------------------------+fromJSVal_Char :: JSVal -> IO (Maybe Char)+fromJSVal_Char x =+ if isNullOrUndefined x+ then pure Nothing+ else Just <$> fromJSValUnchecked_Char x+{-# INLINE fromJSVal_Char #-}+-----------------------------------------------------------------------------+toJSVal_JSString :: JSString -> IO JSVal+toJSVal_JSString (JSString jsval) = pure jsval+{-# INLINE toJSVal_JSString #-}+-----------------------------------------------------------------------------+fromJSVal_Text :: JSVal -> IO (Maybe Text)+fromJSVal_Text x =+ if isNullOrUndefined x+ then pure Nothing+ else Just <$> fromJSValUnchecked_Text x+{-# INLINE fromJSVal_Text #-}+-----------------------------------------------------------------------------+fromJSValUnchecked_Text :: JSVal -> IO Text+fromJSValUnchecked_Text t =+ pure $ textFromJSString (JSString t)+{-# INLINE fromJSValUnchecked_Text #-}+-----------------------------------------------------------------------------+toJSVal_Text :: Text -> IO JSVal+toJSVal_Text t =+ case textToJSString t of+ JSString jsval -> pure jsval+{-# INLINE toJSVal_Text #-}+-----------------------------------------------------------------------------+fromJSVal_Float :: JSVal -> IO (Maybe Float)+fromJSVal_Float x =+ if isNullOrUndefined x+ then pure Nothing+ else Just <$> fromJSValUnchecked_Float x+{-# INLINE fromJSVal_Float #-}+-----------------------------------------------------------------------------+fromJSVal_Bool :: JSVal -> IO (Maybe Bool)+fromJSVal_Bool x =+ if isNullOrUndefined x+ then pure Nothing+ else Just <$> fromJSValUnchecked_Bool x+{-# INLINE fromJSVal_Bool #-}+-----------------------------------------------------------------------------+fromJSVal_Int :: JSVal -> IO (Maybe Int)+fromJSVal_Int x =+ if isNullOrUndefined x+ then pure Nothing+ else Just <$> fromJSValUnchecked_Int x+{-# INLINE fromJSVal_Int #-}+-----------------------------------------------------------------------------+fromJSVal_Double :: JSVal -> IO (Maybe Double)+fromJSVal_Double x =+ if isNullOrUndefined x+ then pure Nothing+ else Just <$> fromJSValUnchecked_Double x+{-# INLINE fromJSVal_Double #-}+-----------------------------------------------------------------------------+fromJSVal_List :: JSVal -> IO (Maybe [JSVal])+fromJSVal_List x = do+ if isNullOrUndefined x+ then pure Nothing+ else do+ arrayLike <- isArray x+ if not arrayLike+ then pure Nothing+ else Just <$> fromJSValUnchecked_List x+{-# INLINE fromJSVal_List #-}+-----------------------------------------------------------------------------+fromJSValUnchecked_List :: JSVal -> IO [JSVal]+fromJSValUnchecked_List x = do+ len <- length x+ forM [ 0 .. len - 1 ] (flip getPropIndex_ffi x)+{-# INLINE fromJSValUnchecked_List #-}+-----------------------------------------------------------------------------+fromJSVal_JSString :: JSVal -> IO (Maybe JSString)+fromJSVal_JSString x = do+ if isNullOrUndefined x+ then pure Nothing+ else Just <$> jsstringFromJSVal x+{-# INLINE fromJSVal_JSString #-}+-----------------------------------------------------------------------------+foreign import javascript unsafe "return $1" jsstringFromJSVal :: JSVal -> IO JSString+-----------------------------------------------------------------------------+isNullOrUndefined :: JSVal -> Bool+isNullOrUndefined x = isNull_ffi x || isUndefined_ffi x+{-# INLINE isNullOrUndefined #-}+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1 === undefined;+ """ isUndefined_ffi :: JSVal -> Bool+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1 === null;+ """ isNull_ffi :: JSVal -> Bool+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return null;+ """ jsNull :: JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe "return globalThis" global :: JSVal+-----------------------------------------------------------------------------+foreign import javascript "wrapper"+ asyncCallback+ :: IO ()+ -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript "wrapper"+ asyncCallback1+ :: (JSVal -> IO ())+ -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript "wrapper"+ asyncCallback2+ :: (JSVal -> JSVal -> IO ())+ -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript "wrapper"+ asyncCallback3+ :: (JSVal -> JSVal -> JSVal -> IO ())+ -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript "wrapper sync"+ syncCallback+ :: IO ()+ -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript "wrapper sync"+ syncCallback1+ :: (JSVal -> IO ())+ -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript "wrapper sync"+ syncCallback2+ :: (JSVal -> JSVal -> IO ())+ -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript "wrapper sync"+ syncCallback3+ :: (JSVal -> JSVal -> JSVal -> IO ())+ -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript "wrapper sync"+ syncCallback'+ :: IO JSVal+ -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript "wrapper sync"+ syncCallback1'+ :: (JSVal -> IO JSVal)+ -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript "wrapper sync"+ syncCallback2'+ :: (JSVal -> JSVal -> IO JSVal)+ -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript "wrapper sync"+ syncCallback3'+ :: (JSVal -> JSVal -> JSVal -> IO JSVal)+ -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return Object.keys($1);+ """+ listProps_ffi :: JSVal -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1.apply($2, $3);+ """+ invokeFunction+ :: JSVal+ -- ^ Func+ -> JSVal+ -- ^ Obj+ -> JSVal+ -- ^ Args+ -> IO JSVal+ -- ^ Return value+-----------------------------------------------------------------------------+foreign import javascript unsafe+ "$3[$1]=$2"+ setPropIndex_ffi+ :: Int+ -- ^ Index+ -> JSVal+ -- ^ Value+ -> JSVal+ -- ^ Object+ -> IO ()+-----------------------------------------------------------------------------+foreign import javascript unsafe+ "$3[$1]=$2"+ setProp_ffi+ :: JSString+ -- ^ Field+ -> JSVal+ -- ^ Value+ -> JSVal+ -- ^ Object+ -> IO ()+-----------------------------------------------------------------------------+-- | Regular FFIs+-----------------------------------------------------------------------------+foreign import javascript unsafe+ "return new $1(...$2)"+ new_ffi+ :: JSVal+ -- ^ Constructor+ -> JSVal+ -- ^ Args+ -> IO JSVal+ -- ^ Return+-----------------------------------------------------------------------------+foreign import javascript unsafe "return {}" create_ffi :: IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe "return $2[$1]"+ getProp_ffi+ :: JSString+ -- ^ Key+ -> JSVal+ -- ^ Value+ -> IO JSVal+ -- ^ Return+-----------------------------------------------------------------------------+-- | Unsafe JS eval, use at your own risk! You have been warned+foreign import javascript unsafe+ """+ return eval($1);+ """ eval_ffi :: JSString -> IO JSVal+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1+ """ fromJSValUnchecked_Int :: JSVal -> IO Int+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1+ """ fromJSValUnchecked_Double :: JSVal -> IO Double+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1+ """ fromJSValUnchecked_Bool :: JSVal -> IO Bool+-----------------------------------------------------------------------------+foreign import javascript unsafe "return $2[$1]"+ getPropIndex_ffi+ :: Int+ -- ^ Key+ -> JSVal+ -- ^ Value+ -> IO JSVal+ -- ^ Return+-----------------------------------------------------------------------------+freeFunction_ffi :: JSVal -> IO ()+freeFunction_ffi = freeJSVal+{-# INLINE freeFunction_ffi #-}+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return requestAnimationFrame($1);+ """ requestAnimationFrame :: JSVal -> IO Int+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return cancelAnimationFrame($1);+ """ cancelAnimationFrame :: Int -> IO ()+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return Array.isArray($1);+ """ isArray :: JSVal -> IO Bool+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return $1.length+ """ length :: JSVal -> IO Int+-----------------------------------------------------------------------------+fromJSVal_Maybe :: JSVal -> IO (Maybe (Maybe JSVal))+fromJSVal_Maybe jsval = do+ if isNullOrUndefined jsval+ then pure (Just Nothing)+ else pure $ Just (Just jsval)+{-# INLINE fromJSVal_Maybe #-}+-----------------------------------------------------------------------------+fromJSValUnchecked_Maybe :: JSVal -> IO (Maybe JSVal)+fromJSValUnchecked_Maybe jsval = do+ if isNullOrUndefined jsval+ then pure Nothing+ else pure (Just jsval)+{-# INLINE fromJSValUnchecked_Maybe #-}+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return parseInt($1);+ """+ parseInt_Unchecked :: JSString -> Double+-----------------------------------------------------------------------------+parseWord :: JSString -> Maybe Word+parseWord string = fromIntegral <$> parseInt string+{-# INLINE parseWord #-}+-----------------------------------------------------------------------------+parseInt :: JSString -> Maybe Int+parseInt string = do+ case parseInt_Unchecked string of+ double | isNaN double -> Nothing+ | otherwise -> Just (round double)+{-# INLINE parseInt #-}+-----------------------------------------------------------------------------+foreign import javascript unsafe+ """+ return parseFloat($1);+ """+ parseDouble_Unchecked :: JSString -> Double+-----------------------------------------------------------------------------+parseDouble :: JSString -> Maybe Double+parseDouble string = do+ case parseDouble_Unchecked string of+ double | isNaN double -> Nothing+ | otherwise -> Just double+{-# INLINE parseDouble #-}+-----------------------------------------------------------------------------+parseFloat :: JSString -> Maybe Float+parseFloat string = realToFrac <$> parseDouble string+{-# INLINE parseFloat #-}+-----------------------------------------------------------------------------
+ ffi/wasm/Miso/DSL/TH.hs view
@@ -0,0 +1,40 @@+-----------------------------------------------------------------------------+{-# LANGUAGE ImportQualifiedPost #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE LambdaCase #-}+-----------------------------------------------------------------------------+module Miso.DSL.TH (evalTH) where+-----------------------------------------------------------------------------+import Control.Exception+import Language.Haskell.TH qualified as TH+import Language.Haskell.TH.Syntax qualified as TH+-----------------------------------------------------------------------------+-- | This is from @amesgen. It's a workaround until we can have proper+-- support for js-sources. It constructs an FFI declaration to import @miso.js@.+--+evalTH :: String -> [TH.Q TH.Type] -> TH.Q TH.Exp+evalTH jsChunk argTys = do+ ffiImportName <- TH.newName . show =<< TH.newName "wasm_ffi_import_eval"+ sig <- mkSig argTys+ let ffiImport =+ TH.ForeignD $+ TH.ImportF+ TH.JavaScript+ TH.Unsafe+ jsChunk+ ffiImportName+ sig+ TH.addTopDecls [ffiImport]++ argNames <- traverse (\_ -> TH.newName "x") argTys+ let argPats = TH.varP <$> argNames+ argExps = TH.varE <$> argNames+ -- Safe FFI imports return a thunk that needs to be evaluated to make sure+ -- that the FFI call actually completed ('unsafeInterleaveIO'-like). To avoid+ -- surprises, use this unconditionally.+ TH.lamE argPats [|evaluate =<< $(TH.appsE $ TH.varE ffiImportName : argExps)|]+ where+ mkSig = \case+ [] -> [t|IO ()|]+ t : ts -> [t|$t -> $(mkSig ts)|]+-----------------------------------------------------------------------------
+ ffi/wasm/Miso/DSL/TH/File.hs view
@@ -0,0 +1,20 @@+-----------------------------------------------------------------------------+{-# LANGUAGE ImportQualifiedPost #-}+{-# LANGUAGE TemplateHaskell #-}+-----------------------------------------------------------------------------+module Miso.DSL.TH.File (evalFile) where+-----------------------------------------------------------------------------+import Language.Haskell.TH qualified as TH+-----------------------------------------------------------------------------+import Miso.DSL.TH (evalTH)+-----------------------------------------------------------------------------+-- | Like 'eval', but read the JS code to evaluate from a file.+evalFile+ :: FilePath+ -- ^ Path to JS file that will be converted into an FFI declaration.+ -> TH.Q TH.Exp+evalFile path = eval_ =<< TH.runIO (readFile path)+ where+ eval_ :: String -> TH.Q TH.Exp+ eval_ chunk = [| $(Miso.DSL.TH.evalTH chunk []) :: IO () |]+-----------------------------------------------------------------------------
+ js/miso.js view
@@ -0,0 +1,1084 @@+// ts/miso/util.ts+var version = "1.9.0.0";+function callFocus(id, delay) {+ var setFocus = function() {+ var e = document.getElementById(id);+ if (e && e.focus)+ e.focus();+ };+ delay > 0 ? setTimeout(setFocus, delay) : setFocus();+}+function callBlur(id, delay) {+ var setBlur = function() {+ var e = document.getElementById(id);+ if (e && e.blur)+ e.blur();+ };+ delay > 0 ? setTimeout(setBlur, delay) : setBlur();+}+function callSelect(id, delay) {+ var setSelect = function() {+ var e = document.getElementById(id);+ if (e && typeof e["select"] === "function")+ e.select();+ };+ delay > 0 ? setTimeout(setSelect, delay) : setSelect();+}+function callSetSelectionRange(id, start, end, delay) {+ var setSetSelectionRange = function() {+ var e = document.getElementById(id);+ if (e && typeof e["setSelectionRange"] === "function")+ e.setSelectionRange(start, end, "none");+ };+ delay > 0 ? setTimeout(setSetSelectionRange, delay) : setSetSelectionRange();+}+function fetchCore(url, method, body, requestHeaders, successful, errorful, responseType) {+ var options = { method, headers: requestHeaders };+ if (body) {+ options["body"] = body;+ }+ let headers = {};+ let status = null;+ try {+ fetch(url, options).then((response) => {+ status = response.status;+ for (const [key, value] of response.headers) {+ headers[key] = value;+ }+ if (!response.ok) {+ throw new Error(response.statusText);+ }+ if (responseType == "json") {+ return response.json();+ } else if (responseType == "text") {+ return response.text();+ } else if (responseType === "arrayBuffer") {+ return response.arrayBuffer();+ } else if (responseType === "blob") {+ return response.blob();+ } else if (responseType === "bytes") {+ return response.bytes();+ } else if (responseType === "formData") {+ return response.formData();+ } else if (responseType === "none") {+ return successful({ error: null, body: null, headers, status });+ }+ }).then((body2) => successful({ error: null, body: body2, headers, status })).catch((body2) => errorful({ error: null, body: body2, headers, status }));+ } catch (err) {+ errorful({ body: null, error: err.message, headers, status });+ }+}+function websocketConnect(url, onOpen, onClose, onMessageText, onMessageJSON, onMessageBLOB, onMessageArrayBuffer, onError, textOnly) {+ try {+ let socket = new WebSocket(url);+ socket.onopen = function() {+ onOpen();+ };+ socket.onclose = function(e) {+ onClose(e);+ };+ socket.onerror = function(error) {+ console.error(error);+ onError("WebSocket error received");+ };+ socket.onmessage = function(msg) {+ if (typeof msg.data === "string") {+ try {+ if (textOnly) {+ if (onMessageText)+ onMessageText(msg.data);+ return;+ }+ const json = JSON.parse(msg.data);+ if (onMessageJSON)+ onMessageJSON(json);+ } catch (err) {+ if (textOnly && onMessageText) {+ onMessageText(msg.data);+ } else {+ onError(err.message);+ }+ }+ } else if (msg.data instanceof Blob) {+ if (onMessageBLOB)+ onMessageBLOB(msg.data);+ } else if (msg.data instanceof ArrayBuffer) {+ if (onMessageArrayBuffer)+ onMessageArrayBuffer(msg.data);+ } else {+ console.error("Received unknown message type from WebSocket", msg);+ onError("Unknown message received from WebSocket");+ }+ };+ return socket;+ } catch (err) {+ onError(err.message);+ }+}+function websocketClose(socket) {+ if (socket) {+ socket.close();+ socket = null;+ }+}+function websocketSend(socket, message) {+ if (message && socket && socket.readyState === WebSocket.OPEN) {+ socket.send(message);+ }+}+function eventSourceConnect(url, onOpen, onMessageText, onMessageJSON, onError, textOnly) {+ try {+ let eventSource = new EventSource(url);+ eventSource.onopen = function() {+ onOpen();+ };+ eventSource.onerror = function() {+ onError("EventSource error received");+ };+ eventSource.onmessage = function(msg) {+ try {+ if (textOnly) {+ if (onMessageText)+ onMessageText(msg.data);+ return;+ }+ const json = JSON.parse(msg.data);+ if (onMessageJSON)+ onMessageJSON(json);+ } catch (err) {+ if (textOnly && onMessageText) {+ onMessageText(msg.data);+ } else {+ onError(err.message);+ }+ }+ };+ return eventSource;+ } catch (err) {+ onError(err.message);+ }+}+function eventSourceClose(eventSource) {+ if (eventSource) {+ eventSource.close();+ eventSource = null;+ }+}+function populateClass(vnode, classes) {+ if (!vnode.classList) {+ vnode.classList = new Set;+ }+ for (const str of classes) {+ for (const c of str.trim().split(" ")) {+ if (c)+ vnode.classList.add(c);+ }+ }+}+function updateRef(current, latest) {+ if (!current.parent) {+ return;+ }+ latest.nextSibling = current.nextSibling ? null : current.nextSibling;+ latest.parent = current.parent;+ current.parent.child = latest;+}+function inline(code, context = {}) {+ const keys = Object.keys(context);+ const values = Object.values(context);+ const func = new Function(...keys, code);+ return func(...values);+}+function typeOf(x) {+ if (x === null || x === undefined)+ return 0;+ if (typeof x === "number")+ return 1;+ if (typeof x === "string")+ return 2;+ if (typeof x === "boolean")+ return 3;+ if (Array.isArray(x))+ return 4;+ return 5;+}+function splitmix32(a) {+ return function() {+ a |= 0;+ a = a + 2654435769 | 0;+ var t = a ^ a >>> 15;+ t = Math.imul(t, 2246822507);+ t = t ^ t >>> 13;+ t = Math.imul(t, 3266489909);+ return ((t ^ t >>> 16) >>> 0) / 4294967296;+ };+}+function getRandomValues() {+ const array = new Uint32Array(1);+ return crypto.getRandomValues(array)[0];+}+function mathRandom() {+ return Math.random();+}+function getDOMRef(tree) {+ switch (tree.type) {+ case 0 /* VComp */:+ return drill(tree);+ default:+ return tree.domRef;+ }+}+function drill(c) {+ if (!c.child)+ throw new Error("'drill' called on an unmounted Component. This should never happen, please make an issue.");+ switch (c.child.type) {+ case 0 /* VComp */:+ return drill(c.child);+ default:+ return c.child.domRef;+ }+}++// ts/miso/dom.ts+function diff(c, n, parent, context) {+ if (!c && !n)+ return;+ else if (!c)+ create(n, parent, context);+ else if (!n)+ destroy(c, parent, context);+ else if (c.type === 2 /* VText */ && n.type === 2 /* VText */) {+ diffVText(c, n, context);+ } else if (c.type === 0 /* VComp */ && n.type === 0 /* VComp */) {+ if (n.key === c.key) {+ n.child = c.child;+ n.componentId = c.componentId;+ if (c.child)+ c.child.parent = n;+ return;+ }+ replace(c, n, parent, context);+ } else if (c.type === 1 /* VNode */ && n.type === 1 /* VNode */) {+ if (n.tag === c.tag && n.key === c.key) {+ n.domRef = c.domRef;+ diffAttrs(c, n, context);+ } else {+ replace(c, n, parent, context);+ }+ } else+ replace(c, n, parent, context);+}+function diffVText(c, n, context) {+ if (c.text !== n.text)+ context.setTextContent(c.domRef, n.text);+ n.domRef = c.domRef;+ return;+}+function replace(c, n, parent, context) {+ switch (c.type) {+ case 2 /* VText */:+ break;+ default:+ callBeforeDestroyedRecursive(c);+ break;+ }+ createElement(parent, 1 /* REPLACE */, getDOMRef(c), n, context);+ switch (c.type) {+ case 2 /* VText */:+ break;+ default:+ callDestroyedRecursive(c);+ break;+ }+}+function destroy(c, parent, context) {+ switch (c.type) {+ case 2 /* VText */:+ break;+ default:+ callBeforeDestroyedRecursive(c);+ break;+ }+ context.removeChild(parent, getDOMRef(c));+ switch (c.type) {+ case 2 /* VText */:+ break;+ default:+ callDestroyedRecursive(c);+ break;+ }+}+function callDestroyedRecursive(c) {+ callDestroyed(c);+ switch (c.type) {+ case 1 /* VNode */:+ for (const child of c.children) {+ if (child.type === 1 /* VNode */ || child.type === 0 /* VComp */) {+ callDestroyedRecursive(child);+ }+ }+ break;+ case 0 /* VComp */:+ if (c.child) {+ if (c.child.type === 1 /* VNode */ || c.child.type === 0 /* VComp */)+ callDestroyedRecursive(c.child);+ }+ break;+ }+}+function callDestroyed(c) {+ if (c.type === 1 /* VNode */ && c.onDestroyed)+ c.onDestroyed();+ if (c.type === 0 /* VComp */)+ unmountComponent(c);+}+function callBeforeDestroyed(c) {+ switch (c.type) {+ case 0 /* VComp */:+ break;+ case 1 /* VNode */:+ if (c.onBeforeDestroyed)+ c.onBeforeDestroyed();+ break;+ default:+ break;+ }+}+function callBeforeDestroyedRecursive(c) {+ callBeforeDestroyed(c);+ switch (c.type) {+ case 1 /* VNode */:+ for (const child of c.children) {+ if (child.type === 2 /* VText */)+ continue;+ callBeforeDestroyedRecursive(child);+ }+ break;+ case 0 /* VComp */:+ if (c.child) {+ if (c.child.type === 1 /* VNode */ || c.child.type === 0 /* VComp */)+ callBeforeDestroyedRecursive(c.child);+ }+ break;+ }+}+function diffAttrs(c, n, context) {+ diffProps(c ? c.props : {}, n.props, n.domRef, n.ns === "svg", context);+ diffClass(c ? c.classList : null, n.classList, n.domRef, context);+ diffCss(c ? c.css : {}, n.css, n.domRef, context);+ diffChildren(c ? c.children : [], n.children, n.domRef, context);+ drawCanvas(n);+}+function diffClass(c, n, domRef, context) {+ if (!c && !n) {+ return;+ }+ if (!c) {+ for (const className of n) {+ context.addClass(className, domRef);+ }+ return;+ }+ if (!n) {+ for (const className of c) {+ context.removeClass(className, domRef);+ }+ return;+ }+ for (const className of c) {+ if (!n.has(className)) {+ context.removeClass(className, domRef);+ }+ }+ for (const className of n) {+ if (!c.has(className)) {+ context.addClass(className, domRef);+ }+ }+ return;+}+function diffProps(cProps, nProps, node, isSvg, context) {+ var newProp;+ for (const c in cProps) {+ newProp = nProps[c];+ if (newProp === undefined) {+ if (isSvg || !(c in node) || c === "disabled") {+ context.removeAttribute(node, c);+ } else {+ context.setAttribute(node, c, "");+ }+ } else {+ if (newProp === cProps[c] && c !== "checked" && c !== "value")+ continue;+ if (isSvg) {+ if (c === "href") {+ context.setAttributeNS(node, "http://www.w3.org/1999/xlink", "href", newProp);+ } else {+ context.setAttribute(node, c, newProp);+ }+ } else if (c in node && !(c === "list" || c === "form")) {+ node[c] = newProp;+ } else {+ context.setAttribute(node, c, newProp);+ }+ }+ }+ for (const n in nProps) {+ if (cProps && cProps[n])+ continue;+ newProp = nProps[n];+ if (isSvg) {+ if (n === "href") {+ context.setAttributeNS(node, "http://www.w3.org/1999/xlink", "href", newProp);+ } else {+ context.setAttribute(node, n, newProp);+ }+ } else if (n in node && !(n === "list" || n === "form")) {+ node[n] = nProps[n];+ } else {+ context.setAttribute(node, n, newProp);+ }+ }+}+function diffCss(cCss, nCss, node, context) {+ context.setInlineStyle(cCss, nCss, node);+}+function shouldSync(cs, ns) {+ if (cs.length === 0 || ns.length === 0)+ return false;+ for (var i = 0;i < cs.length; i++) {+ if (cs[i].key === null || cs[i].key === undefined) {+ return false;+ }+ }+ for (var i = 0;i < ns.length; i++) {+ if (ns[i].key === null || ns[i].key === undefined) {+ return false;+ }+ }+ return true;+}+function diffChildren(cs, ns, parent, context) {+ if (shouldSync(cs, ns)) {+ syncChildren(cs, ns, parent, context);+ } else {+ for (let i = 0;i < Math.max(ns.length, cs.length); i++)+ diff(cs[i], ns[i], parent, context);+ }+}+function populateDomRef(c, context) {+ if (c.ns === "svg") {+ c.domRef = context.createElementNS("http://www.w3.org/2000/svg", c.tag);+ } else if (c.ns === "mathml") {+ c.domRef = context.createElementNS("http://www.w3.org/1998/Math/MathML", c.tag);+ } else {+ c.domRef = context.createElement(c.tag);+ }+}+function callCreated(parent, n, context) {+ if (n.onCreated)+ n.onCreated(n.domRef);+}+function createElement(parent, op, replacing, n, context) {+ switch (n.type) {+ case 2 /* VText */:+ n.domRef = context.createTextNode(n.text);+ switch (op) {+ case 2 /* INSERT_BEFORE */:+ context.insertBefore(parent, n.domRef, replacing);+ break;+ case 0 /* APPEND */:+ context.appendChild(parent, n.domRef);+ break;+ case 1 /* REPLACE */:+ context.replaceChild(parent, n.domRef, replacing);+ break;+ }+ break;+ case 0 /* VComp */:+ mountComponent(parent, op, replacing, n, context);+ break;+ case 1 /* VNode */:+ if (n.onBeforeCreated)+ n.onBeforeCreated();+ populateDomRef(n, context);+ if (n.onCreated)+ n.onCreated(n.domRef);+ diffAttrs(null, n, context);+ switch (op) {+ case 2 /* INSERT_BEFORE */:+ context.insertBefore(parent, n.domRef, replacing);+ break;+ case 0 /* APPEND */:+ context.appendChild(parent, n.domRef);+ break;+ case 1 /* REPLACE */:+ context.replaceChild(parent, n.domRef, replacing);+ break;+ }+ break;+ }+}+function drawCanvas(c) {+ if (c.tag === "canvas" && c.draw)+ c.draw(c.domRef);+}+function unmountComponent(c) {+ c.unmount(c.componentId);+}+function mountComponent(parent, op, replacing, n, context) {+ let mounted = n.mount(parent);+ n.componentId = mounted.componentId;+ n.child = mounted.componentTree;+ mounted.componentTree.parent = n;+ if (mounted.componentTree.type !== 0 /* VComp */) {+ const childDomRef = getDOMRef(mounted.componentTree);+ if (op === 1 /* REPLACE */ && replacing) {+ context.replaceChild(parent, childDomRef, replacing);+ } else if (op === 2 /* INSERT_BEFORE */) {+ context.insertBefore(parent, childDomRef, replacing);+ }+ }+}+function create(n, parent, context) {+ createElement(parent, 0 /* APPEND */, null, n, context);+}+function insertBefore(parent, n, o, context) {+ context.insertBefore(parent, getDOMRef(n), o ? getDOMRef(o) : null);+}+function swapDOMRef(oLast, oFirst, parent, context) {+ context.swapDOMRefs(getDOMRef(oLast), getDOMRef(oFirst), parent);+}+function syncChildren(os, ns, parent, context) {+ var oldFirstIndex = 0, newFirstIndex = 0, oldLastIndex = os.length - 1, newLastIndex = ns.length - 1, tmp, nFirst, nLast, oLast, oFirst, found, node;+ for (;; ) {+ if (newFirstIndex > newLastIndex && oldFirstIndex > oldLastIndex) {+ break;+ }+ nFirst = ns[newFirstIndex];+ nLast = ns[newLastIndex];+ oFirst = os[oldFirstIndex];+ oLast = os[oldLastIndex];+ if (oldFirstIndex > oldLastIndex) {+ diff(null, nFirst, parent, context);+ insertBefore(parent, nFirst, oFirst, context);+ os.splice(newFirstIndex, 0, nFirst);+ newFirstIndex++;+ } else if (newFirstIndex > newLastIndex) {+ tmp = oldLastIndex;+ while (oldLastIndex >= oldFirstIndex) {+ destroy(os[oldLastIndex--], parent, context);+ }+ os.splice(oldFirstIndex, tmp - oldFirstIndex + 1);+ break;+ } else if (oFirst.key === nFirst.key) {+ diff(os[oldFirstIndex++], ns[newFirstIndex++], parent, context);+ } else if (oLast.key === nLast.key) {+ diff(os[oldLastIndex--], ns[newLastIndex--], parent, context);+ } else if (oFirst.key === nLast.key && nFirst.key === oLast.key) {+ swapDOMRef(oLast, oFirst, parent, context);+ swap(os, oldFirstIndex, oldLastIndex);+ diff(os[oldFirstIndex++], ns[newFirstIndex++], parent, context);+ diff(os[oldLastIndex--], ns[newLastIndex--], parent, context);+ } else if (oFirst.key === nLast.key) {+ insertBefore(parent, oFirst, oLast.nextSibling, context);+ os.splice(oldLastIndex, 0, os.splice(oldFirstIndex, 1)[0]);+ diff(os[oldLastIndex--], ns[newLastIndex--], parent, context);+ } else if (oLast.key === nFirst.key) {+ insertBefore(parent, oLast, oFirst, context);+ os.splice(oldFirstIndex, 0, os.splice(oldLastIndex, 1)[0]);+ diff(os[oldFirstIndex++], nFirst, parent, context);+ newFirstIndex++;+ } else {+ found = false;+ tmp = oldFirstIndex;+ while (tmp <= oldLastIndex) {+ if (os[tmp].key === nFirst.key) {+ found = true;+ node = os[tmp];+ break;+ }+ tmp++;+ }+ if (found) {+ os.splice(oldFirstIndex, 0, os.splice(tmp, 1)[0]);+ diff(os[oldFirstIndex++], nFirst, parent, context);+ insertBefore(parent, node, os[oldFirstIndex], context);+ newFirstIndex++;+ } else {+ createElement(parent, 2 /* INSERT_BEFORE */, getDOMRef(oFirst), nFirst, context);+ os.splice(oldFirstIndex++, 0, nFirst);+ newFirstIndex++;+ oldLastIndex++;+ }+ }+ }+}+function swap(os, l, r) {+ const k = os[l];+ os[l] = os[r];+ os[r] = k;+}++// ts/miso/event.ts+function delegator(mount, events, getVTree, debug, context) {+ for (const event of events) {+ context.addEventListener(mount, event.name, function(e) {+ listener(e, mount, getVTree, debug, context);+ }, event.capture);+ }+}+function listener(e, mount, getVTree, debug, context) {+ getVTree(function(vtree) {+ if (Array.isArray(e)) {+ for (const key of e) {+ dispatch(key, vtree, mount, debug, context);+ }+ } else {+ dispatch(e, vtree, mount, debug, context);+ }+ });+}+function dispatch(ev, vtree, mount, debug, context) {+ var target = context.getTarget(ev);+ if (target) {+ let stack = buildTargetToElement(mount, target, context);+ delegateEvent(ev, vtree, stack, debug, context);+ }+}+function buildTargetToElement(element, target, context) {+ var stack = [];+ while (!context.isEqual(element, target)) {+ stack.unshift(target);+ if (target && context.parentNode(target)) {+ target = context.parentNode(target);+ } else {+ return stack;+ }+ }+ return stack;+}+function delegateEvent(event, obj, stack, debug, context) {+ if (!stack.length) {+ if (debug) {+ console.warn('Event "' + event.type + '" did not find an event handler to dispatch on', obj, event);+ }+ return;+ } else if (stack.length > 1) {+ if (obj.type === 2 /* VText */) {+ return;+ } else if (obj.type === 0 /* VComp */) {+ if (!obj.child) {+ if (debug) {+ console.error("VComp has no child property set during event delegation", obj);+ console.error("This means the Component has not been fully mounted, this should never happen");+ throw new Error("VComp has no .child property set during event delegation");+ }+ return;+ }+ return delegateEvent(event, obj.child, stack, debug, context);+ } else if (obj.type === 1 /* VNode */) {+ if (context.isEqual(obj.domRef, stack[0])) {+ const eventObj = obj.events.captures[event.type];+ if (eventObj) {+ const options = eventObj.options;+ if (options.preventDefault)+ event.preventDefault();+ if (!event["captureStopped"]) {+ eventObj.runEvent(event, obj.domRef);+ }+ if (options.stopPropagation) {+ event["captureStopped"] = true;+ }+ }+ stack.splice(0, 1);+ for (const child of obj.children) {+ if (context.isEqual(getDOMRef(child), stack[0])) {+ delegateEvent(event, child, stack, debug, context);+ }+ }+ }+ return;+ }+ } else {+ if (obj.type === 0 /* VComp */) {+ if (obj.child) {+ delegateEvent(event, obj.child, stack, debug, context);+ }+ } else if (obj.type === 1 /* VNode */) {+ const eventCaptureObj = obj.events.captures[event.type];+ if (eventCaptureObj && !event["captureStopped"]) {+ const options = eventCaptureObj.options;+ if (context.isEqual(stack[0], obj.domRef)) {+ if (options.preventDefault)+ event.preventDefault();+ eventCaptureObj.runEvent(event, stack[0]);+ if (options.stopPropagation)+ event["captureStopped"] = true;+ }+ }+ const eventObj = obj.events.bubbles[event.type];+ if (eventObj && !event["captureStopped"]) {+ const options = eventObj.options;+ if (context.isEqual(stack[0], obj.domRef)) {+ if (options.preventDefault)+ event.preventDefault();+ eventObj.runEvent(event, stack[0]);+ if (!options.stopPropagation) {+ propagateWhileAble(obj.parent, event);+ }+ }+ } else {+ if (!event["captureStopped"]) {+ propagateWhileAble(obj.parent, event);+ }+ }+ }+ }+}+function propagateWhileAble(vtree, event) {+ while (vtree) {+ switch (vtree.type) {+ case 2 /* VText */:+ break;+ case 1 /* VNode */:+ const eventObj = vtree.events.bubbles[event.type];+ if (eventObj) {+ const options = eventObj.options;+ if (options.preventDefault)+ event.preventDefault();+ eventObj.runEvent(event, vtree.domRef);+ if (options.stopPropagation) {+ return;+ }+ }+ vtree = vtree.parent;+ break;+ case 0 /* VComp */:+ if (!vtree.eventPropagation)+ return;+ vtree = vtree.parent;+ break;+ }+ }+}+function eventJSON(at, obj) {+ if (typeof at[0] === "object") {+ var ret = [];+ for (var i = 0;i < at.length; i++) {+ ret.push(eventJSON(at[i], obj));+ }+ return ret;+ }+ for (const a of at)+ obj = obj[a];+ var newObj;+ if (obj instanceof Array || "length" in obj && obj["localName"] !== "select") {+ newObj = [];+ for (var j = 0;j < obj.length; j++) {+ newObj.push(eventJSON([], obj[j]));+ }+ return newObj;+ }+ newObj = {};+ for (var key in getAllPropertyNames(obj)) {+ if (obj["localName"] === "input" && (key === "selectionDirection" || key === "selectionStart" || key === "selectionEnd")) {+ continue;+ }+ if (typeof obj[key] == "string" || typeof obj[key] == "number" || typeof obj[key] == "boolean") {+ newObj[key] = obj[key];+ }+ }+ return newObj;+}+function getAllPropertyNames(obj) {+ var props = {}, i = 0;+ do {+ var names = Object.getOwnPropertyNames(obj);+ for (i = 0;i < names.length; i++) {+ props[names[i]] = null;+ }+ } while (obj = Object.getPrototypeOf(obj));+ return props;+}++// ts/miso/context/dom.ts+var eventContext = {+ addEventListener: (mount, event, listener2, capture) => {+ mount.addEventListener(event, listener2, capture);+ },+ delegator: (mount, events, getVTree, debug, ctx) => {+ delegator(mount, events, getVTree, debug, ctx);+ },+ isEqual: (x, y) => {+ return x === y;+ },+ getTarget: (e) => {+ return e.target;+ },+ parentNode: (node) => {+ return node.parentNode;+ }+};+var hydrationContext = {+ getInlineStyle: (node, key) => {+ return node.style[key];+ },+ firstChild: (node) => {+ return node.firstChild;+ },+ lastChild: (node) => {+ return node.lastChild;+ },+ getAttribute: (node, key) => {+ if (key === "class")+ return node.className;+ if (key in node)+ return node[key];+ return node.getAttribute(key);+ },+ getTag: (node) => {+ return node.nodeName;+ },+ getTextContent: (node) => {+ return node.textContent;+ },+ children: (node) => {+ return node.childNodes;+ }+};+var componentContext = {+ mountComponent: function(componentId, model) {+ return;+ },+ unmountComponent: function(componentId) {+ return;+ },+ modelHydration: function(componentId, model) {+ return;+ }+};+var drawingContext = {+ nextSibling: (node) => {+ if (node.nextSibling) {+ switch (node.nextSibling.type) {+ case 0 /* VComp */:+ return drill(node.nextSibling);+ default:+ return node.nextSibling.domRef;+ }+ }+ return null;+ },+ createTextNode: (s) => {+ return document.createTextNode(s);+ },+ createElementNS: (ns, tag) => {+ return document.createElementNS(ns, tag);+ },+ appendChild: (parent, child) => {+ return parent.appendChild(child);+ },+ replaceChild: (parent, n, old) => {+ return parent.replaceChild(n, old);+ },+ removeChild: (parent, child) => {+ return parent.removeChild(child);+ },+ createElement: (tag) => {+ return document.createElement(tag);+ },+ addClass: (className, domRef) => {+ if (className)+ domRef.classList.add(className);+ },+ removeClass: (className, domRef) => {+ if (className)+ domRef.classList.remove(className);+ },+ insertBefore: (parent, child, node) => {+ return parent.insertBefore(child, node);+ },+ swapDOMRefs: (oLast, oFirst, p) => {+ const tmp = oLast.nextSibling;+ p.insertBefore(oLast, oFirst);+ p.insertBefore(oFirst, tmp);+ return;+ },+ setInlineStyle: (cCss, nCss, node) => {+ var result;+ for (const key in cCss) {+ result = nCss[key];+ if (!result) {+ if (key in node.style) {+ node.style[key] = "";+ } else {+ node.style.setProperty(key, "");+ }+ } else if (result !== cCss[key]) {+ if (key in node.style) {+ node.style[key] = result;+ } else {+ node.style.setProperty(key, result);+ }+ }+ }+ for (const n in nCss) {+ if (cCss && cCss[n])+ continue;+ if (n in node.style) {+ node.style[n] = nCss[n];+ } else {+ node.style.setProperty(n, nCss[n]);+ }+ }+ return;+ },+ setAttribute: (node, key, value) => {+ return node.setAttribute(key, value);+ },+ setAttributeNS: (node, ns, key, value) => {+ return node.setAttributeNS(ns, key, value);+ },+ removeAttribute: (node, key) => {+ return node.removeAttribute(key);+ },+ setTextContent: (node, text) => {+ node.textContent = text;+ return;+ },+ flush: () => {+ return;+ },+ getHead: function() {+ return document.head;+ },+ getRoot: function() {+ return document.body;+ }+};++// ts/miso/hydrate.ts+function collapseSiblingTextNodes(vs) {+ var ax = 0, adjusted = vs.length > 0 ? [vs[0]] : [];+ for (var ix = 1;ix < vs.length; ix++) {+ if (adjusted[ax].type === 2 /* VText */ && vs[ix].type === 2 /* VText */) {+ adjusted[ax].text += vs[ix].text;+ continue;+ }+ adjusted[++ax] = vs[ix];+ }+ return adjusted;+}+function hydrate(logLevel, mountPoint, vtree, context, drawingContext2) {+ if (!vtree || !mountPoint)+ return false;+ if (mountPoint.nodeType === 3)+ return false;+ if (!walk(logLevel, vtree, context.firstChild(mountPoint), context, drawingContext2)) {+ if (logLevel) {+ console.warn("[DEBUG_HYDRATE] Could not copy DOM into virtual DOM, falling back to diff");+ }+ while (context.firstChild(mountPoint))+ drawingContext2.removeChild(mountPoint, context.lastChild(mountPoint));+ return false;+ } else {+ if (logLevel) {+ console.info("[DEBUG_HYDRATE] Successfully prerendered page");+ }+ }+ return true;+}+function diagnoseError(logLevel, vtree, node) {+ if (logLevel)+ console.warn("[DEBUG_HYDRATE] VTree differed from node", vtree, node);+}+function walk(logLevel, vtree, node, context, drawingContext2) {+ switch (vtree.type) {+ case 0 /* VComp */:+ let mounted = vtree.mount(node.parentNode);+ vtree.componentId = mounted.componentId;+ vtree.child = mounted.componentTree;+ mounted.componentTree.parent = vtree;+ if (!walk(logLevel, vtree.child, node, context, drawingContext2)) {+ return false;+ }+ break;+ case 2 /* VText */:+ if (node.nodeType !== 3 || vtree.text.trim() !== node.textContent.trim()) {+ diagnoseError(logLevel, vtree, node);+ return false;+ }+ vtree.domRef = node;+ break;+ case 1 /* VNode */:+ if (node.nodeType !== 1) {+ diagnoseError(logLevel, vtree, node);+ return false;+ }+ vtree.domRef = node;+ vtree.children = collapseSiblingTextNodes(vtree.children);+ callCreated(node, vtree, drawingContext2);+ for (var i = 0;i < vtree.children.length; i++) {+ const vdomChild = vtree.children[i];+ const domChild = node.childNodes[i];+ if (!domChild) {+ diagnoseError(logLevel, vdomChild, domChild);+ return false;+ }+ if (!walk(logLevel, vdomChild, domChild, context, drawingContext2)) {+ return false;+ }+ }+ break;+ }+ return true;+}++// ts/index.ts+globalThis["miso"] = {+ hydrationContext,+ eventContext,+ drawingContext,+ componentContext,+ diff,+ hydrate,+ version,+ callBlur,+ callFocus,+ callSelect,+ callSetSelectionRange,+ eventJSON,+ fetchCore,+ eventSourceConnect,+ eventSourceClose,+ websocketConnect,+ websocketClose,+ websocketSend,+ updateRef,+ inline,+ typeOf,+ mathRandom,+ getRandomValues,+ splitmix32,+ populateClass,+ delegateEvent,+ delegator: eventContext.delegator,+ setDrawingContext: function(name) {+ const drawing = globalThis[name]["drawingContext"];+ const events = globalThis[name]["eventContext"];+ const components = globalThis[name]["componentContext"];+ if (!drawing) {+ console.error('Custom rendering engine ("drawingContext") is not defined at globalThis[name].drawingContext', name);+ }+ if (!events) {+ console.error('Custom event delegation ("eventContext") is not defined at globalThis[name].eventContext', name);+ }+ if (!components) {+ console.error('Custom component context ("componentContext") is not defined at globalThis[name].componentContext', name);+ }+ globalThis["miso"]["drawingContext"] = drawing;+ globalThis["miso"]["eventContext"] = events;+ globalThis["miso"]["componentContext"] = components;+ }+};
+ js/miso.prod.js view
@@ -0,0 +1,1 @@+var L="1.9.0.0";function w(U,z){var G=function(){var H=document.getElementById(U);if(H&&H.focus)H.focus()};z>0?setTimeout(G,z):G()}function I(U,z){var G=function(){var H=document.getElementById(U);if(H&&H.blur)H.blur()};z>0?setTimeout(G,z):G()}function V(U,z){var G=function(){var H=document.getElementById(U);if(H&&typeof H.select==="function")H.select()};z>0?setTimeout(G,z):G()}function O(U,z,G,H){var K=function(){var X=document.getElementById(U);if(X&&typeof X.setSelectionRange==="function")X.setSelectionRange(z,G,"none")};H>0?setTimeout(K,H):K()}function P(U,z,G,H,K,X,Q){var Z={method:z,headers:H};if(G)Z.body=G;let _={},$=null;try{fetch(U,Z).then((Y)=>{$=Y.status;for(let[W,J]of Y.headers)_[W]=J;if(!Y.ok)throw new Error(Y.statusText);if(Q=="json")return Y.json();else if(Q=="text")return Y.text();else if(Q==="arrayBuffer")return Y.arrayBuffer();else if(Q==="blob")return Y.blob();else if(Q==="bytes")return Y.bytes();else if(Q==="formData")return Y.formData();else if(Q==="none")return K({error:null,body:null,headers:_,status:$})}).then((Y)=>K({error:null,body:Y,headers:_,status:$})).catch((Y)=>X({error:null,body:Y,headers:_,status:$}))}catch(Y){X({body:null,error:Y.message,headers:_,status:$})}}function f(U,z,G,H,K,X,Q,Z,_){try{let $=new WebSocket(U);return $.onopen=function(){z()},$.onclose=function(Y){G(Y)},$.onerror=function(Y){console.error(Y),Z("WebSocket error received")},$.onmessage=function(Y){if(typeof Y.data==="string")try{if(_){if(H)H(Y.data);return}let W=JSON.parse(Y.data);if(K)K(W)}catch(W){if(_&&H)H(Y.data);else Z(W.message)}else if(Y.data instanceof Blob){if(X)X(Y.data)}else if(Y.data instanceof ArrayBuffer){if(Q)Q(Y.data)}else console.error("Received unknown message type from WebSocket",Y),Z("Unknown message received from WebSocket")},$}catch($){Z($.message)}}function j(U){if(U)U.close(),U=null}function k(U,z){if(z&&U&&U.readyState===WebSocket.OPEN)U.send(z)}function b(U,z,G,H,K,X){try{let Q=new EventSource(U);return Q.onopen=function(){z()},Q.onerror=function(){K("EventSource error received")},Q.onmessage=function(Z){try{if(X){if(G)G(Z.data);return}let _=JSON.parse(Z.data);if(H)H(_)}catch(_){if(X&&G)G(Z.data);else K(_.message)}},Q}catch(Q){K(Q.message)}}function T(U){if(U)U.close(),U=null}function g(U,z){if(!U.classList)U.classList=new Set;for(let G of z)for(let H of G.trim().split(" "))if(H)U.classList.add(H)}function h(U,z){if(!U.parent)return;z.nextSibling=U.nextSibling?null:U.nextSibling,z.parent=U.parent,U.parent.child=z}function y(U,z={}){let G=Object.keys(z),H=Object.values(z);return new Function(...G,U)(...H)}function m(U){if(U===null||U===void 0)return 0;if(typeof U==="number")return 1;if(typeof U==="string")return 2;if(typeof U==="boolean")return 3;if(Array.isArray(U))return 4;return 5}function v(U){return function(){U|=0,U=U+2654435769|0;var z=U^U>>>15;return z=Math.imul(z,2246822507),z=z^z>>>13,z=Math.imul(z,3266489909),((z^z>>>16)>>>0)/4294967296}}function u(){let U=new Uint32Array(1);return crypto.getRandomValues(U)[0]}function l(){return Math.random()}function q(U){switch(U.type){case 0:return S(U);default:return U.domRef}}function S(U){if(!U.child)throw new Error("'drill' called on an unmounted Component. This should never happen, please make an issue.");switch(U.child.type){case 0:return S(U.child);default:return U.child.domRef}}function A(U,z,G,H){if(!U&&!z)return;else if(!U)EU(z,G,H);else if(!z)o(U,G,H);else if(U.type===2&&z.type===2)HU(U,z,H);else if(U.type===0&&z.type===0){if(z.key===U.key){if(z.child=U.child,z.componentId=U.componentId,U.child)U.child.parent=z;return}x(U,z,G,H)}else if(U.type===1&&z.type===1)if(z.tag===U.tag&&z.key===U.key)z.domRef=U.domRef,n(U,z,H);else x(U,z,G,H);else x(U,z,G,H)}function HU(U,z,G){if(U.text!==z.text)G.setTextContent(U.domRef,z.text);z.domRef=U.domRef;return}function x(U,z,G,H){switch(U.type){case 2:break;default:C(U);break}switch(i(G,1,q(U),z,H),U.type){case 2:break;default:R(U);break}}function o(U,z,G){switch(U.type){case 2:break;default:C(U);break}switch(G.removeChild(z,q(U)),U.type){case 2:break;default:R(U);break}}function R(U){switch(KU(U),U.type){case 1:for(let z of U.children)if(z.type===1||z.type===0)R(z);break;case 0:if(U.child){if(U.child.type===1||U.child.type===0)R(U.child)}break}}function KU(U){if(U.type===1&&U.onDestroyed)U.onDestroyed();if(U.type===0)AU(U)}function QU(U){switch(U.type){case 0:break;case 1:if(U.onBeforeDestroyed)U.onBeforeDestroyed();break;default:break}}function C(U){switch(QU(U),U.type){case 1:for(let z of U.children){if(z.type===2)continue;C(z)}break;case 0:if(U.child){if(U.child.type===1||U.child.type===0)C(U.child)}break}}function n(U,z,G){YU(U?U.props:{},z.props,z.domRef,z.ns==="svg",G),XU(U?U.classList:null,z.classList,z.domRef,G),ZU(U?U.css:{},z.css,z.domRef,G),_U(U?U.children:[],z.children,z.domRef,G),qU(z)}function XU(U,z,G,H){if(!U&&!z)return;if(!U){for(let K of z)H.addClass(K,G);return}if(!z){for(let K of U)H.removeClass(K,G);return}for(let K of U)if(!z.has(K))H.removeClass(K,G);for(let K of z)if(!U.has(K))H.addClass(K,G);return}function YU(U,z,G,H,K){var X;for(let Q in U)if(X=z[Q],X===void 0)if(H||!(Q in G)||Q==="disabled")K.removeAttribute(G,Q);else K.setAttribute(G,Q,"");else{if(X===U[Q]&&Q!=="checked"&&Q!=="value")continue;if(H)if(Q==="href")K.setAttributeNS(G,"http://www.w3.org/1999/xlink","href",X);else K.setAttribute(G,Q,X);else if(Q in G&&!(Q==="list"||Q==="form"))G[Q]=X;else K.setAttribute(G,Q,X)}for(let Q in z){if(U&&U[Q])continue;if(X=z[Q],H)if(Q==="href")K.setAttributeNS(G,"http://www.w3.org/1999/xlink","href",X);else K.setAttribute(G,Q,X);else if(Q in G&&!(Q==="list"||Q==="form"))G[Q]=z[Q];else K.setAttribute(G,Q,X)}}function ZU(U,z,G,H){H.setInlineStyle(U,z,G)}function $U(U,z){if(U.length===0||z.length===0)return!1;for(var G=0;G<U.length;G++)if(U[G].key===null||U[G].key===void 0)return!1;for(var G=0;G<z.length;G++)if(z[G].key===null||z[G].key===void 0)return!1;return!0}function _U(U,z,G,H){if($U(U,z))SU(U,z,G,H);else for(let K=0;K<Math.max(z.length,U.length);K++)A(U[K],z[K],G,H)}function WU(U,z){if(U.ns==="svg")U.domRef=z.createElementNS("http://www.w3.org/2000/svg",U.tag);else if(U.ns==="mathml")U.domRef=z.createElementNS("http://www.w3.org/1998/Math/MathML",U.tag);else U.domRef=z.createElement(U.tag)}function t(U,z,G){if(z.onCreated)z.onCreated(z.domRef)}function i(U,z,G,H,K){switch(H.type){case 2:switch(H.domRef=K.createTextNode(H.text),z){case 2:K.insertBefore(U,H.domRef,G);break;case 0:K.appendChild(U,H.domRef);break;case 1:K.replaceChild(U,H.domRef,G);break}break;case 0:JU(U,z,G,H,K);break;case 1:if(H.onBeforeCreated)H.onBeforeCreated();if(WU(H,K),H.onCreated)H.onCreated(H.domRef);switch(n(null,H,K),z){case 2:K.insertBefore(U,H.domRef,G);break;case 0:K.appendChild(U,H.domRef);break;case 1:K.replaceChild(U,H.domRef,G);break}break}}function qU(U){if(U.tag==="canvas"&&U.draw)U.draw(U.domRef)}function AU(U){U.unmount(U.componentId)}function JU(U,z,G,H,K){let X=H.mount(U);if(H.componentId=X.componentId,H.child=X.componentTree,X.componentTree.parent=H,X.componentTree.type!==0){let Q=q(X.componentTree);if(z===1&&G)K.replaceChild(U,Q,G);else if(z===2)K.insertBefore(U,Q,G)}}function EU(U,z,G){i(z,0,null,U,G)}function N(U,z,G,H){H.insertBefore(U,q(z),G?q(G):null)}function DU(U,z,G,H){H.swapDOMRefs(q(U),q(z),G)}function SU(U,z,G,H){var K=0,X=0,Q=U.length-1,Z=z.length-1,_,$,Y,W,J,F,c;for(;;){if(X>Z&&K>Q)break;if($=z[X],Y=z[Z],J=U[K],W=U[Q],K>Q)A(null,$,G,H),N(G,$,J,H),U.splice(X,0,$),X++;else if(X>Z){_=Q;while(Q>=K)o(U[Q--],G,H);U.splice(K,_-K+1);break}else if(J.key===$.key)A(U[K++],z[X++],G,H);else if(W.key===Y.key)A(U[Q--],z[Z--],G,H);else if(J.key===Y.key&&$.key===W.key)DU(W,J,G,H),BU(U,K,Q),A(U[K++],z[X++],G,H),A(U[Q--],z[Z--],G,H);else if(J.key===Y.key)N(G,J,W.nextSibling,H),U.splice(Q,0,U.splice(K,1)[0]),A(U[Q--],z[Z--],G,H);else if(W.key===$.key)N(G,W,J,H),U.splice(K,0,U.splice(Q,1)[0]),A(U[K++],$,G,H),X++;else{F=!1,_=K;while(_<=Q){if(U[_].key===$.key){F=!0,c=U[_];break}_++}if(F)U.splice(K,0,U.splice(_,1)[0]),A(U[K++],$,G,H),N(G,c,U[K],H),X++;else i(G,2,q(J),$,H),U.splice(K++,0,$),X++,Q++}}}function BU(U,z,G){let H=U[z];U[z]=U[G],U[G]=H}function p(U,z,G,H,K){for(let X of z)K.addEventListener(U,X.name,function(Q){NU(Q,U,G,H,K)},X.capture)}function NU(U,z,G,H,K){G(function(X){if(Array.isArray(U))for(let Q of U)e(Q,X,z,H,K);else e(U,X,z,H,K)})}function e(U,z,G,H,K){var X=K.getTarget(U);if(X){let Q=RU(G,X,K);D(U,z,Q,H,K)}}function RU(U,z,G){var H=[];while(!G.isEqual(U,z))if(H.unshift(z),z&&G.parentNode(z))z=G.parentNode(z);else return H;return H}function D(U,z,G,H,K){if(!G.length){if(H)console.warn('Event "'+U.type+'" did not find an event handler to dispatch on',z,U);return}else if(G.length>1){if(z.type===2)return;else if(z.type===0){if(!z.child){if(H)throw console.error("VComp has no child property set during event delegation",z),console.error("This means the Component has not been fully mounted, this should never happen"),new Error("VComp has no .child property set during event delegation");return}return D(U,z.child,G,H,K)}else if(z.type===1){if(K.isEqual(z.domRef,G[0])){let X=z.events.captures[U.type];if(X){let Q=X.options;if(Q.preventDefault)U.preventDefault();if(!U.captureStopped)X.runEvent(U,z.domRef);if(Q.stopPropagation)U.captureStopped=!0}G.splice(0,1);for(let Q of z.children)if(K.isEqual(q(Q),G[0]))D(U,Q,G,H,K)}return}}else if(z.type===0){if(z.child)D(U,z.child,G,H,K)}else if(z.type===1){let X=z.events.captures[U.type];if(X&&!U.captureStopped){let Z=X.options;if(K.isEqual(G[0],z.domRef)){if(Z.preventDefault)U.preventDefault();if(X.runEvent(U,G[0]),Z.stopPropagation)U.captureStopped=!0}}let Q=z.events.bubbles[U.type];if(Q&&!U.captureStopped){let Z=Q.options;if(K.isEqual(G[0],z.domRef)){if(Z.preventDefault)U.preventDefault();if(Q.runEvent(U,G[0]),!Z.stopPropagation)UU(z.parent,U)}}else if(!U.captureStopped)UU(z.parent,U)}}function UU(U,z){while(U)switch(U.type){case 2:break;case 1:let G=U.events.bubbles[z.type];if(G){let H=G.options;if(H.preventDefault)z.preventDefault();if(G.runEvent(z,U.domRef),H.stopPropagation)return}U=U.parent;break;case 0:if(!U.eventPropagation)return;U=U.parent;break}}function B(U,z){if(typeof U[0]==="object"){var G=[];for(var H=0;H<U.length;H++)G.push(B(U[H],z));return G}for(let Z of U)z=z[Z];var K;if(z instanceof Array||"length"in z&&z.localName!=="select"){K=[];for(var X=0;X<z.length;X++)K.push(B([],z[X]));return K}K={};for(var Q in CU(z)){if(z.localName==="input"&&(Q==="selectionDirection"||Q==="selectionStart"||Q==="selectionEnd"))continue;if(typeof z[Q]=="string"||typeof z[Q]=="number"||typeof z[Q]=="boolean")K[Q]=z[Q]}return K}function CU(U){var z={},G=0;do{var H=Object.getOwnPropertyNames(U);for(G=0;G<H.length;G++)z[H[G]]=null}while(U=Object.getPrototypeOf(U));return z}var M={addEventListener:(U,z,G,H)=>{U.addEventListener(z,G,H)},delegator:(U,z,G,H,K)=>{p(U,z,G,H,K)},isEqual:(U,z)=>{return U===z},getTarget:(U)=>{return U.target},parentNode:(U)=>{return U.parentNode}},zU={getInlineStyle:(U,z)=>{return U.style[z]},firstChild:(U)=>{return U.firstChild},lastChild:(U)=>{return U.lastChild},getAttribute:(U,z)=>{if(z==="class")return U.className;if(z in U)return U[z];return U.getAttribute(z)},getTag:(U)=>{return U.nodeName},getTextContent:(U)=>{return U.textContent},children:(U)=>{return U.childNodes}},GU={mountComponent:function(U,z){return},unmountComponent:function(U){return},modelHydration:function(U,z){return}},d={nextSibling:(U)=>{if(U.nextSibling)switch(U.nextSibling.type){case 0:return S(U.nextSibling);default:return U.nextSibling.domRef}return null},createTextNode:(U)=>{return document.createTextNode(U)},createElementNS:(U,z)=>{return document.createElementNS(U,z)},appendChild:(U,z)=>{return U.appendChild(z)},replaceChild:(U,z,G)=>{return U.replaceChild(z,G)},removeChild:(U,z)=>{return U.removeChild(z)},createElement:(U)=>{return document.createElement(U)},addClass:(U,z)=>{if(U)z.classList.add(U)},removeClass:(U,z)=>{if(U)z.classList.remove(U)},insertBefore:(U,z,G)=>{return U.insertBefore(z,G)},swapDOMRefs:(U,z,G)=>{let H=U.nextSibling;G.insertBefore(U,z),G.insertBefore(z,H);return},setInlineStyle:(U,z,G)=>{var H;for(let K in U)if(H=z[K],!H)if(K in G.style)G.style[K]="";else G.style.setProperty(K,"");else if(H!==U[K])if(K in G.style)G.style[K]=H;else G.style.setProperty(K,H);for(let K in z){if(U&&U[K])continue;if(K in G.style)G.style[K]=z[K];else G.style.setProperty(K,z[K])}return},setAttribute:(U,z,G)=>{return U.setAttribute(z,G)},setAttributeNS:(U,z,G,H)=>{return U.setAttributeNS(z,G,H)},removeAttribute:(U,z)=>{return U.removeAttribute(z)},setTextContent:(U,z)=>{U.textContent=z;return},flush:()=>{return},getHead:function(){return document.head},getRoot:function(){return document.body}};function MU(U){var z=0,G=U.length>0?[U[0]]:[];for(var H=1;H<U.length;H++){if(G[z].type===2&&U[H].type===2){G[z].text+=U[H].text;continue}G[++z]=U[H]}return G}function s(U,z,G,H,K){if(!G||!z)return!1;if(z.nodeType===3)return!1;if(!r(U,G,H.firstChild(z),H,K)){if(U)console.warn("[DEBUG_HYDRATE] Could not copy DOM into virtual DOM, falling back to diff");while(H.firstChild(z))K.removeChild(z,H.lastChild(z));return!1}else if(U)console.info("[DEBUG_HYDRATE] Successfully prerendered page");return!0}function a(U,z,G){if(U)console.warn("[DEBUG_HYDRATE] VTree differed from node",z,G)}function r(U,z,G,H,K){switch(z.type){case 0:let Q=z.mount(G.parentNode);if(z.componentId=Q.componentId,z.child=Q.componentTree,Q.componentTree.parent=z,!r(U,z.child,G,H,K))return!1;break;case 2:if(G.nodeType!==3||z.text.trim()!==G.textContent.trim())return a(U,z,G),!1;z.domRef=G;break;case 1:if(G.nodeType!==1)return a(U,z,G),!1;z.domRef=G,z.children=MU(z.children),t(G,z,K);for(var X=0;X<z.children.length;X++){let Z=z.children[X],_=G.childNodes[X];if(!_)return a(U,Z,_),!1;if(!r(U,Z,_,H,K))return!1}break}return!0}globalThis.miso={hydrationContext:zU,eventContext:M,drawingContext:d,componentContext:GU,diff:A,hydrate:s,version:L,callBlur:I,callFocus:w,callSelect:V,callSetSelectionRange:O,eventJSON:B,fetchCore:P,eventSourceConnect:b,eventSourceClose:T,websocketConnect:f,websocketClose:j,websocketSend:k,updateRef:h,inline:y,typeOf:m,mathRandom:l,getRandomValues:u,splitmix32:v,populateClass:g,delegateEvent:D,delegator:M.delegator,setDrawingContext:function(U){let z=globalThis[U].drawingContext,G=globalThis[U].eventContext,H=globalThis[U].componentContext;if(!z)console.error('Custom rendering engine ("drawingContext") is not defined at globalThis[name].drawingContext',U);if(!G)console.error('Custom event delegation ("eventContext") is not defined at globalThis[name].eventContext',U);if(!H)console.error('Custom component context ("componentContext") is not defined at globalThis[name].componentContext',U);globalThis.miso.drawingContext=z,globalThis.miso.eventContext=G,globalThis.miso.componentContext=H}};
− jsbits/delegate.js
@@ -1,140 +0,0 @@-window = typeof window === 'undefined' ? {} : window;-window['oldCallbacks'] = [];-window['currentCallbacks'] = [];--/* Callbacks in ghcjs need to be released. With this function one can register- callbacks that should be released right before diffing.- */-window['registerCallback'] = function registerCallback(cb) {- window['currentCallbacks'].push(cb);-};--/* Swaps out the new calbacks for old callbacks.-The old callbacks should be cleared once the new callbacks have replaced them.-*/-window['swapCallbacks'] = function swapCallbacks() {- window['oldCallbacks'] = window['currentCallbacks'];- window['currentCallbacks'] = [];-};--/* This releases the old callbacks. */-window['releaseCallbacks'] = function releaseCallbacks() {- for (var i in window['oldCallbacks'])- h$release(window['oldCallbacks'][i]);-- window['oldCallbacks'] = [];-};--/* event delegation algorithm */-window['delegate'] = function delegate(mountPointElement, events, getVTree) {- for (var event in events) {- mountPointElement.addEventListener(events[event][0], function(e) {- getVTree(function (obj) {- window['delegateEvent'](e, obj, window['buildTargetToElement'](mountPointElement, e.target), []);- });- }, events[event][1]);- }-};--/* Accumulate parent stack as well for propagation */-window['delegateEvent'] = function delegateEvent (event, obj, stack, parentStack) {-- /* base case, not found */- if (!stack.length) return;-- /* stack not length 1, recurse */- else if (stack.length > 1) {- parentStack.unshift(obj);- for (var o = 0; o < obj.children.length; o++) {- if (obj.children[o]['domRef'] === stack[1]) {- delegateEvent( event, obj.children[o], stack.slice(1), parentStack );- break;- }- }- }-- /* stack.length == 1 */- else {- var eventObj = obj['events'][event.type];- if (eventObj) {- var options = eventObj.options;- if (options['preventDefault'])- event.preventDefault();- eventObj['runEvent'](event);- if (!options['stopPropagation'])- window['propogateWhileAble'] (parentStack, event);- } else {- /* still propagate to parent handlers even if event not defined */- window['propogateWhileAble'] (parentStack, event);- }- }-};--window['buildTargetToElement'] = function buildTargetToElement (element, target) {- var stack = [];- while (element !== target) {- stack.unshift (target);- target = target.parentNode;- }- return stack;-};--window['propogateWhileAble'] = function propogateWhileAble (parentStack, event) {- for (var i = 0; i < parentStack.length; i++) {- if (parentStack[i]['events'][event.type]) {- var eventObj = parentStack[i]['events'][event.type],- options = eventObj['options'];- if (options['preventDefault']) event.preventDefault();- eventObj['runEvent'](event);- if (options['stopPropagation']) break;- }- }-};--/* Walks down obj following the path described by `at`, then filters primitive- values (string, numbers and booleans)*/-window['objectToJSON'] = function objectToJSON (at, obj) {- /* If at is of type [[MisoString]] */- if (typeof at[0] == 'object') {- var ret = [];- for (var i = 0; i < at.length; i++)- ret.push(window['objectToJSON'](at[i], obj));- return ret;- }-- for (var i in at) obj = obj[at[i]];-- /* If obj is a list-like object */- var newObj;- if (obj instanceof Array || ('length' in obj && obj['localName'] !== 'select')) {- newObj = [];- for (var i = 0; i < obj.length; i++)- newObj.push(window['objectToJSON']([], obj[i]));- return newObj;- }-- /* If obj is a non-list-like object */- newObj = {};- for (var i in getAllPropertyNames(obj)){- /* bug in safari, throws TypeError if the following fields are referenced on a checkbox */- /* https://stackoverflow.com/a/25569117/453261 */- /* https://html.spec.whatwg.org/multipage/input.html#do-not-apply */- if ((obj['localName'] === 'input') && (i === 'selectionDirection' || i === 'selectionStart' || i === 'selectionEnd'))- continue;- if (typeof obj[i] == 'string' || typeof obj[i] == 'number' || typeof obj[i] == 'boolean')- newObj[i] = obj[i];- }- return newObj;-};--/* get static and dynamic properties */-function getAllPropertyNames(obj) {- var props = {}, i = 0;- do {- var names = Object.getOwnPropertyNames(obj);- for (i = 0; i < names.length; i++) {- props [names[i]] = null;- }- } while (obj = Object.getPrototypeOf(obj));- return props;-};
− jsbits/diff.js
@@ -1,360 +0,0 @@-/* virtual-dom diffing algorithm, applies patches as detected */-window = typeof window === 'undefined' ? {} : window;-window['diff'] = function diff(currentObj, newObj, parent, doc) {- if (!currentObj && !newObj) return;- else if (!currentObj && newObj) window['createNode'](newObj, parent, doc);- else if (currentObj && !newObj) window['destroyNode'](currentObj, parent);- else {- if (currentObj.type === 'vtext') {- if (newObj.type === 'vnode') window['replaceTextWithElement'](currentObj, newObj, parent, doc);- else window['diffTextNodes'](currentObj, newObj);- } else {- if (newObj.type === 'vnode') window['diffVNodes'](currentObj, newObj, parent, doc);- else window['replaceElementWithText'](currentObj, newObj, parent, doc);- }- }-};--window['destroyNode'] = function destroyNode(obj, parent) {- window['callBeforeDestroyedRecursive'](obj);- parent.removeChild(obj['domRef']);- window['callDestroyedRecursive'](obj);-};--window['callDestroyedRecursive'] = function callDestroyedRecursive(obj) {- window['callDestroyed'](obj);- for (var i in obj.children)- window['callDestroyedRecursive'](obj.children[i]);-};--window['callDestroyed'] = function callDestroyed(obj) {- if (obj['onDestroyed']) obj['onDestroyed']();-};--window['callBeforeDestroyed'] = function callBeforeDestroyed(obj) {- if (obj['onBeforeDestroyed']) obj['onBeforeDestroyed']();-};--window['callBeforeDestroyedRecursive'] = function callBeforeDestroyedRecursive(obj) {- window['callBeforeDestroyed'](obj);- for (var i in obj.children)- window['callBeforeDestroyedRecursive'](obj.children[i]);-};--window['diffTextNodes'] = function diffTextNodes(c, n) {- if (c['text'] !== n['text']) c['domRef'].textContent = n['text'];- n['domRef'] = c['domRef'];-};--window['replaceElementWithText'] = function replaceElementWithText(c, n, parent, doc) {- n['domRef'] = doc.createTextNode(n['text']);- window['callBeforeDestroyedRecursive'](c);- parent.replaceChild(n['domRef'], c['domRef']);- window['callDestroyedRecursive'](c);-};--window['replaceTextWithElement'] = function replaceTextWithElement(c, n, parent, doc) {- window['createElement'](n, doc);- parent.replaceChild(n['domRef'], c['domRef']);- window['callCreated'](n);-};--window['callCreated'] = function callCreated(obj) {- if (obj['onCreated']) obj['onCreated']();-};--window['populate'] = function populate(c, n, doc) {- if (!c) c = {- props: null,- css: null,- children: []- }- window['diffProps'](c['props'], n['props'], n['domRef'], n['ns'] === 'svg');- window['diffCss'](c['css'], n['css'], n['domRef']);- window['diffChildren'](c['children'], n['children'], n['domRef'], doc);-};--window['diffVNodes'] = function diffVNodes(c, n, parent, doc) {- if (c['tag'] === n['tag'] && n['key'] === c['key']) {- n['domRef'] = c['domRef'];- window['populate'](c, n, doc);- } else {- window['createElement'](n, doc);- window['callBeforeDestroyedRecursive'](c);- parent.replaceChild(n['domRef'], c['domRef']);- window['callDestroyedRecursive'](c);- window['callCreated'](n);- }-};--window['diffProps'] = function diffProps(cProps, nProps, node, isSvg) {- var newProp;- /* Is current prop in new prop list? */- for (var c in cProps) {- newProp = nProps[c];- /* If current property no longer exists, remove it */- if (newProp === undefined) {- /* current key is not in node, remove it from DOM, if SVG, remove attribute */- if (isSvg || !(c in node))- node.removeAttribute(c, cProps[c]);- else- node[c] = '';- } else {- /* Already on DOM from previous diff, continue */- if (newProp === cProps[c] && c !== 'checked' && c !== 'value') continue;- if (isSvg) {- if (c === 'href')- node.setAttributeNS('http://www.w3.org/1999/xlink', 'href', newProp);- else- node.setAttribute(c, newProp);- } else if (c in node && !(c === 'list' || c === 'form')) {- node[c] = newProp;- } else {- node.setAttribute(c, newProp);- }- }- }- /* add remaining */- for (var n in nProps) {- if (cProps && cProps[n]) continue;- newProp = nProps[n];- /* Only add new properties, skip (continue) if they already exist in current property map */- if (isSvg) {- if (n === 'href')- node.setAttributeNS('http://www.w3.org/1999/xlink', 'href', newProp);- else- node.setAttribute(n, newProp);- } else if (n in node && !(n === 'list' || n === 'form')) {- node[n] = nProps[n];- } else {- node.setAttribute(n, newProp);- }- }-};--window['diffCss'] = function diffCss(cCss, nCss, node) {- var result;- /* is current attribute in new attribute list? */- for (var c in cCss) {- result = nCss[c];- if (!result) {- /* current key is not in node */- node.style[c] = null;- } else if (result !== cCss[c]) {- node.style[c] = result;- }- }- /* add remaining */- for (var n in nCss) {- if (cCss && cCss[n]) continue;- node.style[n] = nCss[n];- }-};--window['hasKeys'] = function hasKeys(ns, cs) {- return ns.length > 0 && cs.length > 0 && ns[0]['key'] != null && cs[0]['key'] != null;-};--window['diffChildren'] = function diffChildren(cs, ns, parent, doc) {- var longest = ns.length > cs.length ? ns.length : cs.length;- if (window['hasKeys'](ns, cs)) {- window['syncChildren'](cs, ns, parent, doc);- } else {- for (var i = 0; i < longest; i++)- window['diff'](cs[i], ns[i], parent, doc);- }-};--window['createElement'] = function createElement(obj, doc) {- if (obj['ns'] === 'svg') {- obj['domRef'] = doc.createElementNS('http://www.w3.org/2000/svg', obj['tag']);- } else if (obj['ns'] === 'mathml') {- obj['domRef'] = doc.createElementNS('http://www.w3.org/1998/Math/MathML', obj['tag']);- } else {- obj['domRef'] = doc.createElement(obj['tag']);- }- window['populate'](null, obj, doc);-};--window['createNode'] = function createNode(obj, parent, doc) {- if (obj.type === 'vnode') window['createElement'](obj, doc);- else obj['domRef'] = doc.createTextNode(obj['text']);- parent.appendChild(obj['domRef']);- window['callCreated'](obj);-};--/* Child reconciliation algorithm, inspired by kivi and Bobril */-window['syncChildren'] = function syncChildren(os, ns, parent, doc) {- var oldFirstIndex = 0,- newFirstIndex = 0,- oldLastIndex = os.length - 1,- newLastIndex = ns.length - 1,- nFirst, nLast, oLast, oFirst, tmp, found, node;- for (;;) {- /* check base case, first > last for both new and old- [ ] -- old children empty (fully-swapped)- [ ] -- new children empty (fully-swapped)- */- if (newFirstIndex > newLastIndex && oldFirstIndex > oldLastIndex) {- break;- }-- /* Initialize */- nFirst = ns[newFirstIndex];- nLast = ns[newLastIndex];- oFirst = os[oldFirstIndex];- oLast = os[oldLastIndex];- /* No more old nodes, create and insert all remaining nodes- -> [ ] <- old children- -> [ a b c ] <- new children- */- if (oldFirstIndex > oldLastIndex) {- window['diff'](null, nFirst, parent, doc);- /* insertBefore's semantics will append a node if the second argument provided is `null` or `undefined`.- Otherwise, it will insert node['domRef'] before oLast['domRef']. */- parent.insertBefore(nFirst['domRef'], oFirst ? oFirst['domRef'] : null);- os.splice(newFirstIndex, 0, nFirst);- newFirstIndex++;- }- /* No more new nodes, delete all remaining nodes in old list- -> [ a b c ] <- old children- -> [ ] <- new children- */- else if (newFirstIndex > newLastIndex) {- tmp = oldLastIndex;- while (oldLastIndex >= oldFirstIndex) {- parent.removeChild(os[oldLastIndex--]['domRef']);- }- os.splice(oldFirstIndex, tmp - oldFirstIndex + 1);- break;- }- /* happy path, everything aligns, we continue- -> oldFirstIndex -> [ a b c ] <- oldLastIndex- -> newFirstIndex -> [ a b c ] <- newLastIndex- check if nFirst and oFirst align, if so, check nLast and oLast- */- else if (oFirst['key'] === nFirst['key']) {- window['diff'](os[oldFirstIndex++], ns[newFirstIndex++], parent, doc);- } else if (oLast['key'] === nLast['key']) {- window['diff'](os[oldLastIndex--], ns[newLastIndex--], parent, doc);- }- /* flip-flop case, nodes have been swapped, in some way or another- both could have been swapped.- -> [ a b c ] <- old children- -> [ c b a ] <- new children- */- else if (oFirst['key'] === nLast['key'] && nFirst['key'] === oLast['key']) {- window['swapDomRefs'](node, oLast['domRef'], oFirst['domRef'], parent);- window['swap'](os, oldFirstIndex, oldLastIndex);- window['diff'](os[oldFirstIndex++], ns[newFirstIndex++], parent, doc);- window['diff'](os[oldLastIndex--], ns[newLastIndex--], parent, doc);- }- /* Or just one could be swapped (d's align here)- This is top left and bottom right match case.- We move d to end of list, mutate old vdom to reflect the change- We then continue without affecting indexes, hoping to land in a better case- -> [ d a b ] <- old children- -> [ a b d ] <- new children- becomes- -> [ a b d ] <- old children- -> [ a b d ] <- new children- and now we happy path- */- else if (oFirst['key'] === nLast['key']) {- /* insertAfter */- parent.insertBefore(oFirst['domRef'], oLast['domRef'].nextSibling);- /* swap positions in old vdom */- os.splice(oldLastIndex,0,os.splice(oldFirstIndex,1)[0]);- window['diff'](os[oldLastIndex--], ns[newLastIndex--], parent, doc);- }- /* This is top right and bottom lefts match case.- We move d to end of list, mutate old vdom to reflect the change- -> [ b a d ] <- old children- -> [ d b a ] <- new children- becomes- -> [ d b a ] <- old children- -> [ d b a ] <- new children- and now we happy path- */- else if (oLast['key'] === nFirst['key']) {- /* insertAfter */- parent.insertBefore(oLast['domRef'], oFirst['domRef']);- /* swap positions in old vdom */- os.splice(oldFirstIndex,0, os.splice(oldLastIndex,1)[0]);- window['diff'](os[oldFirstIndex++], nFirst, parent, doc);- newFirstIndex++;- }-- /* The 'you're screwed' case, nothing aligns, pull the ripcord, do something more fancy- This can happen when the list is sorted, for example.- -> [ a e c ] <- old children- -> [ b e d ] <- new children- */- else {- /* final case, perform linear search to check if new key exists in old map, decide what to do from there */- found = false;- tmp = oldFirstIndex;- while (tmp <= oldLastIndex) {- if (os[tmp]['key'] === nFirst['key']) {- found = true;- node = os[tmp];- break;- }- tmp++;- }- /* If new key was found in old map this means it was moved, hypothetically as below- -> [ a e b c ] <- old children- -> [ b e a j ] <- new children- ^- In the above case 'b' has been moved, so we need to insert 'b' before 'a' in both vDOM and DOM- We also increase oldFirstIndex and newFirstIndex.-- This results in new list below w/ updated index position- -> [ b a e c ] <- old children- -> [ b e a j ] <- new children- ^- */- if (found) {- /* Move item to correct position */- os.splice(oldFirstIndex,0, os.splice(tmp,1)[0]);- /* optionally perform `diff` here */- window['diff'](os[oldFirstIndex++], nFirst, parent, doc);- /* Swap DOM references */- parent.insertBefore(node['domRef'], os[oldFirstIndex]['domRef']);- /* increment counters */- newFirstIndex++;- }- /* If new key was *not* found in the old map this means it must now be created, example below- -> [ a e d c ] <- old children- -> [ b e a j ] <- new children- ^-- In the above case 'b' does not exist in the old map, so we create a new element and DOM reference.- We then insertBefore in both vDOM and DOM.-- -> [ b a e d c ] <- old children- -> [ b e a j ] <- new children- ^- */- else {- window['createElement'](nFirst, doc);- parent.insertBefore(nFirst['domRef'], oFirst['domRef']);- os.splice(oldFirstIndex++, 0, nFirst);- newFirstIndex++;- oldLastIndex++;- }- }- }-};--window['swapDomRefs'] = function swapDomRefs(tmp,a,b,p) {- tmp = a.nextSibling;- p.insertBefore(a,b);- p.insertBefore(b,tmp);-};--window['swap']= function swap(os,l,r) {- var k = os[l];- os[l] = os[r];- os[r] = k;-};
− jsbits/isomorphic.js
@@ -1,97 +0,0 @@-window = typeof window === 'undefined' ? {} : window;-window['collapseSiblingTextNodes'] = function collapseSiblingTextNodes(vs) {- if (!vs) { return []; }- var ax = 0, adjusted = vs.length > 0 ? [vs[0]] : [];- for (var ix = 1; ix < vs.length; ix++) {- if (adjusted[ax]['type'] === 'vtext' && vs[ix]['type'] === 'vtext') {- adjusted[ax]['text'] += vs[ix]['text'];- continue;- }- adjusted[++ax] = vs[ix];- }- return adjusted;-}--window['copyDOMIntoVTree'] = function copyDOMIntoVTree(logLevel,mountPoint, vtree, doc) {- if (!doc) { doc = window.document; }- var mountChildIdx = 0, node;- // If script tags are rendered first in body, skip them.- if (!mountPoint) {- if (doc.body.childNodes.length > 0) {- node = doc.body.firstChild;- } else {- node = doc.body.appendChild (doc.createElement('div'));- }- } else if (mountPoint.childNodes.length === 0) {- node = mountPoint.appendChild (doc.createElement('div'));- } else {- while (mountPoint.childNodes[mountChildIdx] && (mountPoint.childNodes[mountChildIdx].nodeType === Node.TEXT_NODE || mountPoint.childNodes[mountChildIdx].localName === 'script')){- mountChildIdx++;- }- if (!mountPoint.childNodes[mountChildIdx]) {- node = doc.body.appendChild (doc.createElement('div'));- } else {- node = mountPoint.childNodes[mountChildIdx];- }- }-- if (!window['walk'](logLevel,vtree, node, doc)) {- if (logLevel) {- console.warn('Could not copy DOM into virtual DOM, falling back to diff');- }- // Remove all children before rebuilding DOM- while (node.firstChild) node.removeChild(node.lastChild);- vtree['domRef'] = node;- window['populate'](null, vtree, doc);- return false;- }- if (logLevel) {- console.info ('Successfully prendered page');- }- return true;-}--window['diagnoseError'] = function diagnoseError(logLevel, vtree, node) {- if (logLevel) console.warn('VTree differed from node', vtree, node);-}--window['walk'] = function walk(logLevel, vtree, node, doc) {- // This is slightly more complicated than one might expect since- // browsers will collapse consecutive text nodes into a single text node.- // There can thus be fewer DOM nodes than VDOM nodes.- var vdomChild,- domChild;-- vtree['domRef'] = node;-- // Fire onCreated events as though the elements had just been created.- window['callCreated'](vtree);-- vtree.children = window['collapseSiblingTextNodes'](vtree.children);- for (var i = 0; i < vtree.children.length; i++) {- vdomChild = vtree['children'][i];- domChild = node.childNodes[i];- if (!domChild) {- window['diagnoseError'](logLevel,vdomChild, domChild);- return false;- }- if (vdomChild.type === 'vtext') {- if (domChild.nodeType !== Node.TEXT_NODE) {- window['diagnoseError'](logLevel, vdomChild, domChild);- return false;- }-- if (vdomChild['text'] === domChild.textContent) {- vdomChild['domRef'] = domChild;- } else {- window['diagnoseError'](logLevel, vdomChild, domChild);- return false;- }- } else {- if (domChild.nodeType !== Node.ELEMENT_NODE) return false;- vdomChild['domRef'] = domChild;- if(!window['walk'](logLevel, vdomChild, domChild, doc)) return false;- }- }- return true;-}
− jsbits/util.js
@@ -1,14 +0,0 @@-window = typeof window === 'undefined' ? {} : window;-window['callFocus'] = function callFocus(id) {- setTimeout(function(){- var ele = document.getElementById(id);- if (ele && ele.focus) ele.focus()- }, 50);-}--window['callBlur'] = function callBlur(id) {- setTimeout(function(){- var ele = document.getElementById(id);- if (ele && ele.blur) ele.blur()- }, 50);-}
− jsstring-src/Miso/String.hs
@@ -1,149 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE OverloadedStrings #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--------------------------------------------------------------------------------- |--- Module : Miso.String--- Copyright : (C) 2016-2025 David M. Johnson--- License : BSD3-style (see the file LICENSE)--- Maintainer : David M. Johnson <code@dmj.io>--- Stability : experimental--- Portability : non-portable------------------------------------------------------------------------------module Miso.String (- ToMisoString (..)- , FromMisoString (..)- , fromMisoString- , MisoString- , module Data.JSString- , module Data.Monoid- , ms- ) where--import Data.Aeson-import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as BL-import Data.Char-import Data.JSString-import qualified Data.JSString as JS-import Data.JSString.Text-import Data.Monoid-import qualified Data.Text as T-import qualified Data.Text.Encoding as T-import qualified Data.Text.Lazy as LT-import qualified Data.Text.Lazy.Encoding as LT-import Prelude hiding (foldr)-import Text.StringLike (StringLike(..))---- | String type swappable based on compiler-type MisoString = JS.JSString--#ifdef ghcjs_HOST_OS--- | `ToJSON` for `MisoString`-instance ToJSON MisoString where- toJSON = String . textFromJSString---- | `FromJSON` for `MisoString`-instance FromJSON MisoString where- parseJSON =- withText "Not a valid string" $ \x ->- pure (toMisoString x)-#endif---- | Convenience class for creating `MisoString` from other string-like types-class ToMisoString str where- toMisoString :: str -> MisoString---- | Class used to parse a 'MisoString'. Like a safe 'Read' for 'MisoString'-class FromMisoString t where- -- -- | Reads a `MisoString`- fromMisoStringEither :: MisoString -> Either String t---- | Reads a 'MisoString', throws an error when decoding--- fails. Use `fromMisoStringEither` for as a safe alternative.-fromMisoString :: FromMisoString a => MisoString -> a-fromMisoString s =- case fromMisoStringEither s of- Left err -> error err- Right x -> x---- | Convenience function, shorthand for `toMisoString`-ms :: ToMisoString str => str -> MisoString-ms = toMisoString--instance ToMisoString MisoString where- toMisoString = id-instance ToMisoString String where- toMisoString = JS.pack-instance ToMisoString T.Text where- toMisoString = textToJSString-instance ToMisoString LT.Text where- toMisoString = lazyTextToJSString-instance ToMisoString B.ByteString where- toMisoString = toMisoString . T.decodeUtf8-instance ToMisoString BL.ByteString where- toMisoString = toMisoString . LT.decodeUtf8-instance ToMisoString Float where- toMisoString = JS.pack . show-instance ToMisoString Double where- toMisoString = JS.pack . show-instance ToMisoString Int where- toMisoString = JS.pack . show-instance ToMisoString Word where- toMisoString = JS.pack . show--instance FromMisoString MisoString where- fromMisoStringEither = Right-instance FromMisoString String where- fromMisoStringEither = Right . JS.unpack-instance FromMisoString T.Text where- fromMisoStringEither = Right . textFromJSString-instance FromMisoString LT.Text where- fromMisoStringEither = Right . lazyTextFromJSString-instance FromMisoString B.ByteString where- fromMisoStringEither = fmap T.encodeUtf8 . fromMisoStringEither-instance FromMisoString BL.ByteString where- fromMisoStringEither = fmap LT.encodeUtf8 . fromMisoStringEither-instance FromMisoString Float where- fromMisoStringEither = fmap realToFrac . jsStringToDoubleEither-instance FromMisoString Double where- fromMisoStringEither = jsStringToDoubleEither-instance FromMisoString Int where- fromMisoStringEither = parseInt-instance FromMisoString Word where- fromMisoStringEither = parseWord--jsStringToDoubleEither :: JS.JSString -> Either String Double-jsStringToDoubleEither s = let d = read $ JS.unpack s- in if isNaN d then Left "jsStringToDoubleEither: parse failed"- else Right d---parseWord :: MisoString -> Either String Word-parseWord s = case JS.uncons s of- Nothing -> Left "parseWord: parse error"- Just (c,s') -> JS.foldl' k (pDigit c) s'- where- pDigit c | isDigit c = Right . fromIntegral . digitToInt $ c- | otherwise = Left "parseWord: parse error"- k ea c = (\a x -> 10*a + x) <$> ea <*> pDigit c--parseInt :: MisoString -> Either String Int-parseInt s = case JS.uncons s of- Just ('-',s') -> ((-1)*) . fromIntegral <$> parseWord s'- _ -> fromIntegral <$> parseWord s--instance StringLike MisoString where- uncons = JS.uncons- toString = JS.unpack- fromChar = JS.singleton- strConcat = JS.concat- empty = JS.empty- strNull = JS.null- cons = JS.cons- append = JS.append- strMap = JS.map
miso.cabal view
@@ -1,173 +1,221 @@ cabal-version: 2.2 name: miso-version: 1.8.7.0+version: 1.9.0.0 category: Web, Miso, Data Structures license: BSD-3-Clause license-file: LICENSE author: David M. Johnson <code@dmj.io> maintainer: David M. Johnson <code@dmj.io>-homepage: http://github.com/dmjio/miso-copyright: Copyright (c) 2016-2025 David M. Johnson-bug-reports: https://github.com/dmjio/miso/issues+homepage: https://haskell-miso.org/+copyright: Copyright (c) 2016-2026 David M. Johnson+bug-reports: https://github.com/haskell-miso/miso/issues build-type: Simple extra-source-files: README.md synopsis: A tasty Haskell front-end web framework description:- Miso is a small, production-ready, "isomorphic" Haskell front-end framework featuring a virtual-dom, recursive diffing / patching algorithm, event delegation, event batching, SVG, Server-sent events, Websockets, type-safe servant-style routing and an extensible Subscription-based subsystem. Inspired by Elm, Redux and Bobril. Miso is pure by default, but side effects (like XHR) can be introduced into the system via the Effect data type. Miso makes heavy use of the GHCJS FFI and therefore has minimal dependencies.+ Miso is a small, production-ready, component-oriented, isomorphic Haskell front-end web and mobile framework featuring a virtual-dom, recursive diffing / patching algorithm, event delegation, event batching, SVG, Server-sent events, Websockets, type-safe servant-style routing and an extensible Subscription-based subsystem. Inspired by Elm and React. Miso is pure by default, but side effects can be introduced into the system via the Effect data type. Miso makes heavy use of the GHC FFI and therefore has minimal dependencies. extra-source-files: README.md -flag tests+source-repository head+ type: git+ location: https://github.com/haskell-miso/miso.git++common cpp+ if impl(ghcjs) || arch(javascript)+ cpp-options:+ -DGHCJS_BOTH+ if impl(ghcjs)+ cpp-options:+ -DGHCJS_OLD+ elif arch(javascript)+ cpp-options:+ -DGHCJS_NEW+ elif arch(wasm32)+ cpp-options:+ -DWASM+ else+ cpp-options:+ -DVANILLA++ if flag(production)+ cpp-options:+ -DPRODUCTION++ if flag(ssr)+ cpp-options:+ -DSSR++ if flag(benchmark)+ cpp-options:+ -DBENCH++common client+ if impl(ghcjs) || arch(javascript) || arch(wasm32)+ if flag(production)+ js-sources:+ js/miso.prod.js+ else+ js-sources:+ js/miso.js++flag benchmark+ manual:+ True default: False description:- Builds Miso's tests+ When enabled this outputs (in milliseconds) the time it+ takes to build the virtual DOM on page load. -flag jsaddle- manual: True+flag production+ manual:+ True default: False description:- Compile with JSaddle+ Uses miso's production quality JS (miso.prod.js).+ This is built from calling "bun build --production" -flag ios- manual: True+flag ssr+ manual:+ True default: False description:- Cross compile to iOS+ Used to indicate if SSR (server-side rendering) is being used. Defaults to false.+ Enable when performing hydration / server rendering of Html using ToHtml. -flag jsstring-only- manual: True+flag template-haskell+ manual:+ True default: False description:- Always set MisoString = JSString--executable tests- default-language:- Haskell2010- main-is:- Main.hs- if !(impl(ghcjs) || arch(javascript)) || !flag(tests)- buildable: False- else- ghcjs-options:- -dedupe- cpp-options:- -DGHCJS_BROWSER- hs-source-dirs:- tests- build-depends:- aeson,- base < 5,- bytestring,- ghcjs-base,- QuickCheck,- quickcheck-instances,- miso,- http-types,- network-uri,- http-api-data,- containers,- scientific,- servant,- text,- unordered-containers,- transformers,- vector+ Checks if template-haskell is enabled. If so, allows Miso.Lens.TH library+ import:+ client,+ cpp default-language: Haskell2010+ other-modules:+ Miso.Delegate+ Miso.Diff+ Miso.DSL.FFI+ Miso.Hydrate+ Miso.FFI.Internal+ Miso.Runtime exposed-modules: Miso- Miso.Util- Miso.Dev+ Miso.Binding+ Miso.Canvas+ Miso.Concurrent+ Miso.Date+ Miso.Data.Map+ Miso.Data.Set+ Miso.Data.Array+ Miso.DSL+ Miso.Effect+ Miso.Event+ Miso.Event.Decoder+ Miso.Event.Types+ Miso.EventSource+ Miso.Fetch+ Miso.FFI Miso.Html Miso.Html.Element Miso.Html.Event Miso.Html.Property- Miso.Html.Types- Miso.Delegate- Miso.Diff- Miso.Event- Miso.Event.Decoder- Miso.Event.Types+ Miso.Html.Render+ Miso.JSON+ Miso.JSON.Lexer+ Miso.JSON.Parser+ Miso.JSON.Types+ Miso.Lens+ Miso.Mathml+ Miso.Mathml.Element+ Miso.Mathml.Property+ Miso.Media+ Miso.Navigator+ Miso.Prelude+ Miso.Property+ Miso.PubSub+ Miso.Random Miso.Router- Miso.Effect- Miso.Effect.Storage- Miso.Effect.DOM- Miso.FFI- Miso.FFI.History- Miso.FFI.SSE- Miso.FFI.Storage- Miso.FFI.WebSocket- Miso.JSBits+ Miso.Reload+ Miso.Runtime.Internal+ Miso.State Miso.Subscription Miso.Subscription.History Miso.Subscription.Keyboard Miso.Subscription.Mouse- Miso.Subscription.WebSocket Miso.Subscription.Window- Miso.Subscription.SSE+ Miso.Subscription.OnLine+ Miso.Subscription.Util Miso.Svg- Miso.Svg.Attribute+ Miso.Svg.Property Miso.Svg.Element Miso.Svg.Event- Miso.Types- Miso.Mathml- Miso.Mathml.Element+ Miso.Storage Miso.String+ Miso.CSS+ Miso.CSS.Color+ Miso.CSS.Types+ Miso.Types+ Miso.Util+ Miso.Util.Lexer+ Miso.Util.Parser Miso.WebSocket- if !(impl(ghcjs) || arch(javascript))- exposed-modules:- Miso.TypeLevel- other-modules:- Miso.Concurrent- ghc-options:- -Wall- hs-source-dirs:- src- if impl(ghcjs) || arch(javascript) || flag (jsstring-only)++ -- Live reload (meant for WASM or Vanilla)+ c-sources:+ cbits/foreign.c++ -- FFI declarations+ if arch(javascript) || impl(ghcjs) hs-source-dirs:- jsstring-src- else+ ffi/js+ build-depends:+ ghcjs-base -any++ if impl(ghcjs)+ build-depends:+ ghcjs-prim++ elif arch(wasm32) hs-source-dirs:- text-src- build-depends:- aeson,- base < 5,- bytestring,- containers,- file-embed,- http-api-data,- http-types,- jsaddle,- lucid,- network-uri,- servant,- tagsoup,- text,- transformers- if impl(ghcjs) || arch(javascript)+ ffi/wasm build-depends:- ghcjs-base+ ghc-experimental,+ template-haskell >= 2.21 && < 2.25+ exposed-modules:+ Miso.DSL.TH+ Miso.DSL.TH.File+ other-modules:+ Data.JSString else+ hs-source-dirs:+ ffi/ghc++ if flag (template-haskell) && !impl(ghcjs)+ exposed-modules:+ Miso.Lens.TH+ Miso.String.QQ+ Miso.FFI.QQ build-depends:- servant-lucid- if impl(ghcjs) || arch(javascript) || flag (jsaddle)- if flag (ios)- cpp-options:- -DIOS- if impl(ghcjs) || arch(javascript)- js-sources:- jsbits/diff.js- jsbits/delegate.js- jsbits/isomorphic.js- jsbits/util.js+ template-haskell >= 2.21 && < 2.25 -source-repository head- type: git- location: https://github.com/dmjio/miso.git+ ghc-options:+ -Wall+ hs-source-dirs:+ src+ build-depends:+ base < 5,+ bytestring < 0.13,+ containers < 0.9,+ transformers < 0.6.2.0,+ mtl < 2.4,+ text < 2.2
src/Miso.hs view
@@ -1,190 +1,859 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE KindSignatures #-}--#ifdef IOS-#else-{-# LANGUAGE TemplateHaskell #-}-#endif--------------------------------------------------------------------------------- |--- Module : Miso--- Copyright : (C) 2016-2025 David M. Johnson--- License : BSD3-style (see the file LICENSE)--- Maintainer : David M. Johnson <code@dmj.io>--- Stability : experimental--- Portability : non-portable------------------------------------------------------------------------------module Miso- ( miso- , startApp- , sink- , module Miso.Effect- , module Miso.Event- , module Miso.Html- , module Miso.Subscription-#ifndef ghcjs_HOST_OS- , module Miso.TypeLevel-#endif- , module Miso.Types- , module Miso.Router- , module Miso.Util- , module Miso.FFI- , module Miso.WebSocket- ) where--import Control.Concurrent-import Control.Monad-import Control.Monad.IO.Class-import Data.IORef-import Data.List-import Data.Sequence ((|>))-import qualified Data.Sequence as S-import qualified JavaScript.Object.Internal as OI-import System.IO.Unsafe-import System.Mem.StableName--#ifndef ghcjs_HOST_OS-import Language.Javascript.JSaddle (eval, waitForAnimationFrame)-#ifdef IOS-import Miso.JSBits-#else-import GHCJS.Types (JSString)-import Data.FileEmbed-#endif-#else-import JavaScript.Web.AnimationFrame-#endif--import Miso.Concurrent-import Miso.Delegate-import Miso.Diff-import Miso.Effect-import Miso.Event-import Miso.FFI-import Miso.Html-import Miso.Router-import Miso.Subscription-#ifndef ghcjs_HOST_OS-import Miso.TypeLevel-#endif-import Miso.Types-import Miso.Util-import Miso.WebSocket---- | Helper function to abstract out common functionality between `startApp` and `miso`-common- :: Eq model- => App model action- -> model- -> (Sink action -> JSM (IORef VTree))- -> JSM ()-common App {..} m getView = do-#ifndef ghcjs_HOST_OS-#ifdef IOS- mapM_ eval [delegateJs,diffJs,isomorphicJs,utilJs]-#else- _ <- eval ($(embedStringFile "jsbits/delegate.js") :: JSString)- _ <- eval ($(embedStringFile "jsbits/diff.js") :: JSString)- _ <- eval ($(embedStringFile "jsbits/isomorphic.js") :: JSString)- _ <- eval ($(embedStringFile "jsbits/util.js") :: JSString)-#endif-#endif- -- init Notifier- Notify {..} <- liftIO newNotify- -- init empty actions- actionsRef <- liftIO (newIORef S.empty)- let writeEvent a = void . liftIO . forkIO $ do- atomicModifyIORef' actionsRef $ \as -> (as |> a, ())- notify- -- init global sink- liftIO (writeIORef sinkRef writeEvent)- -- init Subs- forM_ subs $ \sub ->- sub writeEvent- -- Hack to get around `BlockedIndefinitelyOnMVar` exception- -- that occurs when no event handlers are present on a template- -- and `notify` is no longer in scope- void . liftIO . forkIO . forever $ threadDelay (1000000 * 86400) >> notify- -- Retrieves reference view- viewRef <- getView writeEvent- -- know thy mountElement- mountEl <- mountElement mountPoint- -- Begin listening for events in the virtual dom- delegator mountEl viewRef events- -- Process initial action of application- writeEvent initialAction- -- Program loop, blocking on SkipChan-- let- loop !oldModel = liftIO wait >> do- -- Apply actions to model- actions <- liftIO $ atomicModifyIORef' actionsRef $ \actions -> (S.empty, actions)- let (Acc newModel effects) = foldl' (foldEffects writeEvent update)- (Acc oldModel (pure ())) actions- effects- oldName <- liftIO $ oldModel `seq` makeStableName oldModel- newName <- liftIO $ newModel `seq` makeStableName newModel- when (oldName /= newName && oldModel /= newModel) $ do- swapCallbacks- newVTree <- runView (view newModel) writeEvent- oldVTree <- liftIO (readIORef viewRef)- void $ waitForAnimationFrame- (diff mountPoint) (Just oldVTree) (Just newVTree)- releaseCallbacks- liftIO (atomicWriteIORef viewRef newVTree)- syncPoint- loop newModel- loop m---- | Runs an isomorphic miso application.--- Assumes the pre-rendered DOM is already present-miso :: Eq model => (URI -> App model action) -> JSM ()-miso f = do- app@App {..} <- f <$> getCurrentURI- common app model $ \writeEvent -> do- let initialView = view model- VTree (OI.Object iv) <- flip runView writeEvent initialView- mountEl <- mountElement mountPoint- -- Initial diff can be bypassed, just copy DOM into VTree- copyDOMIntoVTree (logLevel == DebugPrerender) mountEl iv- let initialVTree = VTree (OI.Object iv)- -- Create virtual dom, perform initial diff- liftIO (newIORef initialVTree)--sinkRef :: IORef (Sink action)-{-# NOINLINE sinkRef #-}-sinkRef = unsafePerformIO $ newIORef (\_ -> pure ())---- | Global sink exposed as a backdoor--- Meant for usage in long running IO actions, or custom callbacks--- Good for integrating with third-party components.-sink :: Sink action-sink = unsafePerformIO (readIORef sinkRef)---- | Runs a miso application-startApp :: Eq model => App model action -> JSM ()-startApp app@App {..} =- common app model $ \writeEvent -> do- let initialView = view model- initialVTree <- flip runView writeEvent initialView- (diff mountPoint) Nothing (Just initialVTree)- liftIO (newIORef initialVTree)---- | Helper-foldEffects- :: Sink action- -> (action -> model -> Effect action model)- -> Acc model -> action -> Acc model-foldEffects snk update = \(Acc model as) action ->- case update action model of- Effect newModel effs -> Acc newModel newAs- where- newAs = as >> do- forM_ effs $ \eff -> forkJSM (eff snk)--data Acc model = Acc !model !(JSM ())+-----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskell #-}+-----------------------------------------------------------------------------+{-# OPTIONS_GHC -Wno-duplicate-exports #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso+-- Copyright : (C) 2016-2026 David M. Johnson (@dmjio)+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- = miso 🍜+--+-- @miso@ is a library for building web and native user interface applications in Haskell. See the [GitHub group](https://github.com/haskell-miso).+--+-- It provides a [React](https://react.dev)-like programming experience for a simple [Haskell](https://haskell.org) dialect that emphasizes+--+-- * performance+-- * purity+-- * simplicity+-- * extensibility+-- * composability+--+-- miso supports common areas that arise naturally in web development:+--+-- * __DOM manipulation__: @miso@ uses a [Virtual DOM](https://en.wikipedia.org/wiki/Virtual_DOM) with diffing algorithm that is+-- responsible for all DOM modification and 'Component' lifecycle hooks.+--+-- * __Event delegation__: All event listeners are attached to a top-level element+-- (typically @\<body\>@). When raised, events are routed through the virtual DOM+-- to Haskell event handlers which cause application state changes. Internally @miso@+-- virtualizes both the @capture@ and @bubble@ phases of the browser when it performs event routing.+--+-- * __Prerendering__: Prerendering is a process where the server delivers HTML+-- to the client before the JavaScript (or Web Assembly) application bootstraps.+-- Instead of performing an initial draw, the application will create and populate the virtual DOM from the actual DOM.+-- This is a process known as \"hydration\". This avoids unnecessary page draws on initial page+-- load and enhances search engine optimization. @miso@ provides its own HTML rendering+-- ("Miso.Html.Render") to render HTML on the server and the 'miso' function exists on the client to \"hydrate\"+-- the virtual DOM with the DOM.+--+-- * __Components__: A 'Component' can be considered an instance of a @miso@ application. A 'Component'+-- contains user-defined state, logic for updating this state, and a function+-- for creating UI templates from this user-defined state. 'Component' can nest other 'Component' because @miso@+-- is defined recursively.+--+-- * __Custom renderers__: The underlying DOM operations are able to be abstracted.+-- This allows a custom rendering engine to be used. This is seen in the [miso-lynx](https://github.com/haskell-miso/miso-lynx) project+-- (which allows miso to target mobile phone devices).+--+-- * __Lifecycle hooks__: 'Component' expose 'Miso.Types.mount' and 'Miso.Types.unmount' lifecycle hooks. This allow users to define custom logic that will+-- execute when a 'Component' mounts or unmounts. 'Miso.Event.onCreated' and 'Miso.Event.onDestroyed' are 'VNode' specific lifecycle hooks.+-- These hooks are commonly used for 'Component' communication and for third-party integration with JavaScript libraries.+--+-- * __State management__: 'Component' @model@ state can be manipulated using "Miso.Lens" or "Miso.State" in response to application events.+--+-- = The Model-View-Update pattern+--+-- The core type of miso is 'Component'. The 'Component' API adheres to the [Elm](https://elm-lang.org)+-- MVU (model-view-update) interface. This is similar to a left-fold, where the 'Component' @model@+-- will be updated via a list of @action@ given a specific 'Miso.Types.update' function, and rendered via 'Miso.Types.view'.+--+-- * __model__: This can be any user-defined type in Haskell. An 'Eq' constraint+-- is required. We recommend using the default derived 'Eq' instance.+--+-- * __view__: @'view' :: model -> 'View' model action@+-- This is the templating function that is used to construct a new virtual DOM+-- (or HTML if rendering on the server).+--+-- * __update__: @'update' :: action -> 'Effect' parent model action@+-- The 'update' function handles how the 'model' evolves over time in response+-- to events that are raised by the application. This function takes any @action@,+-- updating the @model@ and optionally introducing 'IO' into the system.+--+-- = Your first t'Component'+--+-- To define a 'Component' the 'component' smart constructor can be used.+-- Below is an example of a simple counter 'Component'.+--+-- @+-- -----------------------------------------------------------------------------+-- module Main where+-- -----------------------------------------------------------------------------+-- import Miso+-- import Miso.Lens+-- import qualified Miso.Html.Element as H+-- import qualified Miso.Html.Event as HE+-- import qualified Miso.Html.Property as HP+-- -----------------------------------------------------------------------------+-- * - The type of the parent Component 'model'+-- | * - The type of the current Component's 'model'+-- | | * - The type of the action that updates the 'model'+-- | | |+-- counter :: 'Component' parent Int Action+-- counter = 'vcomp' m u v+-- where+-- m :: Int+-- m = 0+--+-- u :: Action -> 'Effect' parent Int Action+-- u = \\case+-- Add -> 'this' += 1+-- Subtract -> 'this' -= 1+--+-- v :: Int -> 'View' Int Action+-- v x = H.div_+-- [ H.button_ [ HE.onClick Add, HP.id_ "add" ] [ "+" ]+-- , text (ms x)+-- , H.button_ [ HE.onClick Subtract, HP.id_ "subtract" ] [ "-" ]+-- ]+-- -----------------------------------------------------------------------------+-- main :: IO ()+-- main = 'startApp' 'defaultEvents' counter+-- -----------------------------------------------------------------------------+-- data Action+-- = Add+-- | Subtract+-- deriving (Eq, Show)+-- -----------------------------------------------------------------------------+-- @+--+-- = Running your first t'Component'+--+-- The 'startApp' (or 'miso') functions are used to run the above t'Component'.+--+-- @+-- main :: IO ()+-- main = 'startApp' 'defaultEvents' counter+-- @+--+-- The 'startApp' function is what we recommend using first. It sets up event listeners and performs the initial page draw.+-- The 'startApp' function assumes that @\<body\>@ is empty, and it will begin drawing the 'Component' 'View' from @\<body\>@.+--+-- The 'miso' function (and also the 'prerender' function) assume that @\<body\>@ has already been populated by the results of the 'view' function.+-- Instead of drawing, 'miso' will perform hydration.+-- If the structures do not match 'miso' will fallback to drawing the page from scratch (clearing the contents of @\<body\>@ first).+--+-- It is possible to execute an initial action when a t'Component' is first mounted. See the 'mount' (and similarly 'unmount') hooks.+--+-- @+--+-- data Action = Init+--+-- main :: IO ()+-- main = 'startApp' 'defaultEvents' counter { 'mount' = Just Init }+--+-- update :: 'App' model Action+-- update = \\case+-- Init -> 'io_' ('consoleLog' "hello world!")+-- @+--+-- = 'Component' composition+--+-- @miso@ 'Component' can contain other 'Component'. This is+-- accomplished through the 'Component' mounting combinator ('+>'). This combinator+-- is responsible for encoding a typed 'Component' hierarchy, allowing 'Component'+-- type-safe read-only access to their @parent@ model state.+--+-- This combinator unifies the parent @model@ with the child @parent@, and+-- subsequently the grandchild @parent@ unifies with the child @model@. This+-- gives us a correct-by-construction 'Component' hierarchy.+--+-- @+-- ('+>')+-- :: forall child model action a . Eq child+-- => 'MisoString'+-- -> 'Component' model child action+-- -> 'View' model a+-- key '+>' vcomp = 'VComp' (Just (toKey key)) ('SomeComponent' vcomp)+-- @+--+-- Practically, using this combinator looks like:+--+-- @+-- view :: Int -> 'View' Int action+-- view x = 'div_' [ 'id_' "container" ] [ "counter" '+>' counter ]+-- @+--+-- You'll notice the @\"counter\"@ string was specified. This is a unique 'Key'+-- to identify a 'Component' at runtime. These keys are very important when+-- diffing two 'Component' together. When intentionally replacing 'Component' it is important+-- to specify a new 'Key', otherwise the 'Component' will not be unmounted.+--+-- It is possible to mount a component using the 'mount_' function, which avoids specifying a 'key_', but this should only be used+-- when the user is certain they will not be diffing their 'Component' with another 'Component'. When in doubt, use the ('+>') combinator+-- and 'key_' your 'Component'.+--+-- Lastly, note also the signature of 'startApp'.+--+-- @+-- 'startApp' :: 'Eq' model => 'Events' -> 'App' model action -> IO ()+-- @+--+-- The 'App' type signature is a synonym for 'Component' 'ROOT'+--+-- @+-- type 'App' model action = 'Component' 'ROOT' model action+-- @+--+-- 'ROOT' is a type tag that encodes a 'Component' as top-level. Which means it has no @parent@, hence we mark @parent@ as 'ROOT'.+--+-- @+-- data 'ROOT'+-- @+--+-- 'startApp' and 'miso' will always infer @parent@ as 'ROOT'.+--+-- = 'VComp' lifecycle hooks+--+-- 'Component' are mounted on the fly during diffing. All t'Component` are equipped with `mount` and `unmount` hooks. This allows the defining of custom actions that will be processed in response to lifecycle events.+--+-- * 'Miso.Types.mount'+-- * 'Miso.Types.unmount'+--+-- = 'VNode' lifecycle hooks+--+-- Similar to t'Component' lifecycle hooks, all 'Miso.Types.VNode' also expose lifecycle hooks.+--+-- * 'Miso.Event.onBeforeCreated'+-- * 'Miso.Event.onCreated' / 'Miso.Event.onCreatedWith'+-- * 'Miso.Event.onBeforeDestroyed' / 'Miso.Event.onBeforeDestroyedWith'+-- * 'Miso.Event.onDestroyed'+--+-- These are convenient for initializing and deinitializing third-party libraries (as seen below with [highlight.js](https://highlightjs.org/))+--+-- @+-- {-# LANGUAGE QuasiQuotes -#}+-- {-# LANGUAGE MultilineStrings -#}+--+-- import Miso+-- import Miso.FFI.QQ (js)+--+-- data Action = Highlight DOMRef+--+-- update :: Action -> 'Effect' parent model Action+-- update = \\case+-- Highlight domRef -> 'io_' $ do+-- ['js'| hljs.highlight(${domRef}) |]+--+-- view :: model -> 'View' model Action+-- view x =+-- 'code_'+-- [ 'onCreatedWith' Highlight+-- ]+-- [ """+-- function addOne (x) { return x + 1; }+-- """+-- ]+-- @+--+-- As a convention, the @*with@ variant of 'VNode' lifecycle hooks (e.g. 'Miso.Event.onCreatedWith') provide the target 'DOMRef' in the callback function (shown above).+--+-- = 'Key'+--+-- A 'Key' is a unique identifier used to optimize diffing.+--+-- Virtual DOM nodes can be \"keyed\" (See 'key_'). Keys have multiple meanings in @miso@ (and react).+--+-- * Keys are used to optimize child node list diffing.+--+-- When two lists of elements are being diffed, as long as they all have unique keys, diffing large child lists will be much faster. This optimization automatically occurs when all the elements in a 'VNode' child list contain unique keys. Unless all 'View' nodes in a child list are keyed, this optimization will not fire.+--+-- * Keys are used to compare two identical nodes.+--+-- If two `VNode` are being compared (or two `VComp`) and their keys differ, the old node will be destroyed and a new one created. Otherwise, the underlying DOM node won't be removed, but its properties will be diffed. In the case of diffing two t'Component' (the 'VComp' case), if the keys differ, the 'unmount' phase will be triggered for the old 'VComp' and the 'mount' phase will be triggered for the new 'Component'. The underlying DOM reference will be replaced.+--+-- See the 'key_' property for usage (and smart constructors like 'textKey_' and ('+>') as well).+--+-- @+-- 'ul_'+-- []+-- [ 'li_' [ 'key_' "key-1" ] [ "a" ]+-- , 'li_' [ 'key_' "key-2" ] [ "b" ]+-- , "key-3" '+>' counter+-- , 'textKey' "key-4" "text here"+-- ]+-- @+--+-- = t'View' DSL+--+-- The 'View' type is the core type for templating a web page. It is similar to+-- a [Rose tree](https://en.wikipedia.org/wiki/Rose_tree) data structure. This is how the Virtual DOM is constructed. It is+-- mutually recursive with the 'Component' type (via the 'view' function), which allows us to embed+-- 'Component' inside other 'Component'.+--+-- @+-- data 'View' model action+-- = 'VNode' 'Namespace' 'Tag' ['Attribute' action] ['View' model action]+-- | 'VText' (Maybe 'Key') 'MisoString'+-- | 'VComp' (Maybe 'Key') ('SomeComponent' model)+-- @+--+-- 'VNode' and 'VText' have a one-to-one mapping from the virtual DOM to the physical DOM. The 'VComp' constructor is abstract and does not contain a reference to the physical DOM. The existential type of 'SomeComponent' is defined recursively in terms of 'View' and is what allows us to embed other polymorphic 'Component'.+--+-- @+-- data 'SomeComponent' parent+-- = forall model action . Eq model+-- => 'SomeComponent' ('Component' parent model action)+-- @+--+-- The smart constructors:+--+-- * 'node', 'vnode'+-- * 'text', 'vtext'+-- * 'component', 'vcomp'+-- * ('+>')+--+-- are used to build 'VNode', 'VText' and 'VComp' respectively. A list of all the smart constructors defined in terms of 'node' (e.g. 'Miso.Html.Element.div_') can be found in "Miso.Html.Element".+--+-- = 'Events'+--+-- * Event Delegation+--+-- By default all events are delegated through @\<body\>@. Miso supports both @capture@ and @bubble@ phases of browser events.+-- Users can handle both phases in their applications.+--+-- * Using events+--+-- Miso exposes a 'defaultEvents' for convenience, these events are commonly used events and listened for on @\<body\>@. They get routed through the 'View' to the virtual DOM node that raised the event. Other 'Events' are exposed as conveniences (e.g. 'touchEvents'). All events required by all 'Component' must be combined together for use when running your application (e.g. @keyboardEvents <> touchEvents@).+--+-- @+-- 'touchEvents' :: 'Events'+-- 'touchEvents' = M.fromList+-- [ ("touchstart", 'BUBBLE')+-- , ("touchcancel", 'BUBBLE')+-- , ("touchmove", 'BUBBLE')+-- , ("touchend", 'BUBBLE')+-- ]+-- @+--+-- * Defining event handlers+--+-- Users can define their own event handlers using the 'Miso.Event.on' combinator. By default this will define an event in the 'Miso.Event.Types.BUBBLE' phase. See 'Miso.Event.onCapture' for handling events during the 'Miso.Event.Types.CAPTURE' phase. See the the module "Miso.Html.Event" for many predefined events.+--+-- @+-- 'onChangeWith' :: ('MisoString' -> 'DOMRef' -> action) -> 'Attribute' action+-- 'onChangeWith' = 'on' "change" 'valueDecoder'+-- @+--+-- The @*with@ variant of events (e.g. 'Miso.Event.onChangeWith') provides the target 'DOMRef' in the callback function.+--+-- * Decoding events+--+-- After an event has been raised, one can extract information from the event for use in their application. This is accomplished through a 'Decoder'. Many common decoders are available for use in "Miso.Event.Decoder".+--+-- @+-- data 'Decoder' a+-- = 'Decoder'+-- { 'decoder' :: 'Value' -> 'Parser' a+-- , 'decodeAt' :: 'DecodeTarget'+-- }+--+-- -- | Example of a custom 'Decoder' for the @value@ property of an event target.+-- 'valueDecoder' :: 'Decoder' 'MisoString'+-- 'valueDecoder' = Decoder {..}+-- where+-- decodeAt = 'DecodeTarget' ["target"]+-- decoder = 'withObject' "target" $ \\o -> o .: "value"+-- @+--+-- = Attributes / Properties+--+-- The 'Attribute' type allows us to define web handlers that map browser events to+-- Haskell data types (e.g. 'Miso.Html.Event.onClick'), along with specifying properties on DOM elements+-- (like 'Miso.Html.Property.className' and 'Miso.Html.Property.id_'). See "Miso.Property" and "Miso.Html.Property" for more information.+--+-- @+-- 'div_' [ 'id_' "some-id", 'className' "some-class" ] [ ]+-- @+--+-- = 'Effect'+--+-- The 'Effect' type is used to mutate the @model@ over time in response to @action@.+-- 'Effect' also allows 'IO' to be scheduled for evaluation by the @miso@ scheduler.+--+-- Note: 'IO' is never evaluated inside of 'Effect', it is only scheduled.+-- There is no 'MonadIO' instance for 'Effect'.+--+-- The 'Effect' type is defined as a 'RWS'.+--+-- @+-- type 'Effect' parent model action = 'RWS' ('ComponentInfo' parent) ['Schedule' action] model ()+-- @+--+-- * The 'Control.Monad.Reader' portion of 'Effect' is 'ComponentInfo'. 'ask', 'asks', 'Miso.Lens.view' can be used to access its fields.+-- * The 'Control.Monad.Writer' portion of 'Effect' is used to schedule t'IO' actions. 'tell' can be used to create a 'Schedule' for an 'IO' action that is executed according to 'Synchronicity'. See also 'withSink' for usage.+-- * The 'Control.Monad.State' portion of 'Effect' is used to manipulate the @model@. 'get', 'put', 'modify', and the 'Control.Monad.State.MonadState' lenses in t'Miso.Lens.Lens' can be used to modify the @model@.+--+-- 'IO' can be performed either synchronously or asynchronously. By default all 'IO' is asynchronous+--+-- == Asynchronous 'IO'+--+-- * 'io': Used to introduce asynchronous 'io' into the system, see also the 'io_' variant.+--+-- * 'withSink': The core function (from which most other combinators are defined)+-- that gives users access to the underlying event 'Sink'. This also allows us to+-- introduce 'IO' into the system. The @miso@ scheduler attaches exception+-- handlers to all 'IO' actions.+--+-- * For maximum flexibility, the 'MonadWriter' instance ('tell') can be used to schedule 'IO' (see the 'withSink' implementation).+--+-- == Synchronous 'IO'+--+-- * 'sync': Forces the scheduler to evaluate 'IO' synchronously. It is+-- recommended to use the 'io' function by default, 'sync' *will* block the scheduler.+--+-- == 'Sink'+--+-- @+-- type 'Sink' a => a -> 'IO' ()+-- @+--+-- The 'Sink' function allows one to write any @action@ to the global event queue.+--+-- == Managing 'model' state.+--+-- Any 'MonadState' function is allowed for use when manipulating @model@, 'Miso.State.get', 'Miso.State.put', etc. See "Miso.State".+--+-- The 'MonadReader' instances allows the retrieval of 'ComponentInfo' within 'Effect'.+-- 'ComponentInfo' provides the current 'ComponentId' the @parent@ 'ComponentId', and the 'DOMRef' ('_componentDOMRef') that the 'Component' is mounted on.+--+-- = 'Component' communication+--+-- == Asynchronous communication+--+-- 'Component' are able to communicate asynchronously via a message-passing system.+-- The miso runtime exposes a few primitives to allow t'Component' communication.+--+-- * 'broadcast'+-- * 'mail'+-- * 'mailParent'+--+-- All t'Component' have a 'mailbox' that can receive messages (as t'Miso.JSON.Value') from other t'Component'.+-- This is meant to be used with the 'checkMail' function. The 'mail' function allows a 'Component' to send a specific message (as 'Value') to another t'Component' via its t'ComponentId'.+-- The 'ComponentId' can be found in the 'Effect' monad. Using 'ask' will return a t'ComponentInfo'. The 'Component' receiving+-- the message will find it in its 'mailbox'.+--+-- * "Miso.PubSub"+--+-- miso has support for the publisher / subscriber concurrency pattern. See the "Miso.PubSub" module for more information.+--+-- == Synchronous communication+--+-- * "Miso.Binding"+--+-- Experimental support for data bindings (where 'Component' model can synchronize fields via a 'Miso.Lens.Lens' in response to model differences along the parent-child relationship). See the "Miso.Binding" module for more information, and the [miso-reactive](https://github.com/haskell-miso/miso-reactive) example. *Warning*: This is still considered experimental.+--+-- == Parent access+--+-- * 'parent'+--+-- While not direct communication, a 'Component' can asynchronously receive read-only access to its @parent@ state via the 'parent' function.+--+-- = Subscriptions+--+-- A t'Sub' is any long-running operation that is external to a 'Component', but that can write+-- to a 'Component' 'Sink'. 'Sub' come in two flavors, a dynamic 'Sub' (via 'startSub' / 'stopSub') and 'subs'.+--+-- * 'subs'+--+-- @+-- main :: IO ()+-- main = 'startApp' 'defaultEvents' app { 'subs' = [ timerSub ] }+--+-- timerSub :: 'Sub' Action+-- timerSub sink = 'forever' $ ('threadDelay' 100000) >> sink Log+--+-- data Action = Log+-- @+--+-- The 'subs' field of 'Component' contains 'Sub' that exist for the lifetime of that 'Component'.+-- When a 'Component' unmounts, these 'Sub' will be stopped, and their resources finalized.+--+-- @+-- 'onLineSub' :: (Bool -> action) -> 'Sub' action+-- 'onLineSub' f sink = 'Miso.Subscription.Util.createSub' acquire release sink+-- where+-- release (cb1, cb2) = do+-- FFI.windowRemoveEventListener "online" cb1+-- FFI.windowRemoveEventListener "offline" cb2+-- acquire = do+-- cb1 <- FFI.windowAddEventListener "online" (const $ sink (f True))+-- cb2 <- FFI.windowAddEventListener "offline" (const $ sink (f False))+-- pure (cb1, cb2)+-- @+--+-- * 'startSub' / 'stopSub'+--+-- At times its necessary to dynamically generate a 'Sub' in reponse to an event (e.g. starting a "Miso.WebSocket" connection+-- when a user logs in). The 'startSub' and 'stopSub' functions facilitate dynamic 'Sub' creation / removal.+--+-- @+-- update = \\case+-- StartTimer -> 'startSub' ("timer" :: MisoString) timerSub+-- StopTimer -> 'stopSub' "timer"+-- Log -> 'io_' ('consoleLog' "log")+-- where+-- timerSub :: 'Sub' Action+-- timerSub sink = 'Control.Monad.forever' $ ('Control.Concurrent.threadDelay' 100000) >> sink Log+--+-- data Action = Log+-- @+--+-- * 'Miso.Subscription.Util.createSub'+--+-- 'Miso.Subscription.Util.createSub' is a helper function for creating a 'Sub' using the 'Control.Exception.bracket' pattern.+-- This ensures that event listeners can be unregistered when a 'Component' unmounts. For example usage+-- please see the "Miso.Subscription" sub modules. 'createSub' is only meant to be used in scenarios where+-- custom event listeners are required (shown below).+--+-- = (2D/3D) Canvas support+--+-- Miso has full 2D and 3D canvas support. See the "Miso.Canvas" module, the [miso-canvas](https://github.com/haskell-miso/miso-canvas2d) example, along with the [three-miso](https://github.com/haskell-miso/three-miso) package.+--+-- = 'Control.Monad.State.State' management+--+-- A simple 'Miso.Lens.Lens' implementation is included with miso, this was done for convenience, to minimize dependencies, reduce payload size, and provide a simpler interface. See "Miso.Lens". This is a simple lens formulation that exposes many common 'MonadState' lenses (e.g. @'+='@) that work in the 'Effect' monad. "Miso.Lens" is not required for use, any lens library will also work with miso.+--+-- = HTML+--+-- Miso's virtual DOM DSL ('Miso.Types.View') type can be repurposed to render HTML. See the "Miso.Html.Render" module for more information. This uses the 'Miso.Html.Render.ToHtml' class.+--+-- = JavaScript EDSL+--+-- Miso provides a Javascript DSL (inspired by [jsaddle](https://hackage.haskell.org/package/jsaddle)) via "Miso.DSL".+-- See the 'Miso.DSL.ToJSVal' / 'Miso.DSL.FromJSVal' typeclasses when marshaling to and from Haskell to JavaScript. See also the 'Miso.DSL.jsg'+-- function for accessing JavaScript objects that exist in the global scope.+--+-- @+-- document :: 'JSVal' <- 'jsg' "document" :: IO 'JSVal'+-- len :: 'Int' <- 'fromJSValUnchecked' =<< (document ! "body" ! "children" ! "length")+-- @+--+-- = QuasiQuotation (@inline-js@)+--+-- Along with "Miso.DSL", a JavaScript QuasiQuoter is now included (See "Miso.FFI.QQ"). This makes it easy to+-- integrate miso with any third-party JavaScript library. The bindings in scope can be used inside the QuasiQuoter, which+-- will utilize their 'Miso.DSL.ToJSVal' instances. When returning values from the QuasiQuoter, the 'Miso.DSL.FromJSVal' instance will+-- be used Haskell.+--+-- @+--+-- {-# LANGUAGE QuasiQuotes #-}+--+-- import Miso.FFI.QQ ('js')+--+-- update :: Action -> 'Effect' parent model Action+-- update = \\case+-- Log msg -> io_ [js| console.log(${msg}) |]+--+-- data Action = Log MisoString+-- @+--+-- = Routing+--+-- miso exposes its own internal router. See "Miso.Router" for more information. The router is inspired by both the [servant](https://hackage.haskell.org/package/servant) and the [web-routes](https://hackage.haskell.org/package/web-routes) package. The router has its own 'Sub' called 'Miso.Router.routerSub' meant for easy integration with the History API.+--+-- = 'MisoString'+--+-- miso includes its own string type named t'MisoString'. This is the preferred string type to use+-- in order to maximize application performance. Since strings are ubiquitous in applications we+-- want to minimize the copying of these strings between the JS and Haskell heaps. t'MisoString' accomplishes this.+-- t'MisoString' is a synonym for t'JSString' when using the JS / WASM backends. When using vanilla GHC+-- it is t'Data.Text'. See "Miso.String" for more information.+--+-- For string conversions see the 'ms', 'fromMisoString' functions and 'ToMisoString' / 'FromMisoString' classes.+--+-- t'MisoString' is also used in the "Miso.Util.Lexer" and "Miso.Util.Parser" modules.+--+-- = JSON+--+-- "Miso.JSON" is a [microaeson](https://hackage.haskell.org/package/microaeson)+-- implementation that uses t'MisoString'. This is done for performance reasons and to minimize the dependency burden. "Miso.JSON" is used+-- in "Miso.Event.Decoder", "Miso.Fetch", "Miso.WebSocket" modules respectively.+--+-- = Styles+--+-- Miso prescribes no exact CSS style usage. It is up to the user's discretion on how best to handle styles in their application. Inline styles, external stylesheets and the "Miso.CSS" DSL can all be used. See also [miso-ui](https://ui.haskell-miso.org) for an example of what is possible.+--+-- = Development+--+-- When developing miso applications interactively it is possible to append 'styles' and 'scripts' to the @\<head\>@ portion of+-- the page when the 'Component' mounts. This is a convenience only meant to be used in development. We recommend guarding the usage behind a flag.+--+-- @+-- main :: 'IO' ()+-- main = 'startApp' 'defaultEvents' counter+-- where+-- app = counter+-- #ifdef INTERACTIVE+-- { 'scripts' = [ 'Src' "https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js" ]+-- , 'styles' = [ 'Href' "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" ]+-- }+-- #endif+-- @+--+-- See the [miso-sampler](https://github.com/haskell-miso/miso-sampler) repository for more information.+--+-- = Debugging+--+-- Sometimes things can go wrong. Common errors like using `onClick` but not listening for the the 'click' event are common.+-- These are errors that cannot be caught statically. These can be detected by enabling 'DebugAll'. Currently, debugging event delegation+-- and page hydration is supported.+--+-- * 'DebugHydrate'+-- * 'DebugEvents'+--+-- @+-- counter { 'logLevel' = 'DebugAll' }+-- @+--+-- = Internals+--+-- Internally miso uses a global event queue and a scheduler to process all events raised by 'Component' throughout the lifetime of+-- an application. Events are processed in FIFO order, batched by the 'Component' that raised them.+--+-- = Prerendering+--+-- Prerendering is the process of delivering HTML from a web server before the client loads and performs any drawing to the page. In miso it comes in two flavors, static+-- or dynamic prerendering. Static prerendering assumes no model state needs to be shared between the server and client. Dynamic uses 'hydrateModel' to share @model@ state.+--+-- == Static prerendering+--+-- miso provides the 'prerender' and 'miso' functions to facilitate static prerendering. Any page can be generated from a miso 'View' using the 'Miso.Render.toHtml' instance.+--+-- A simple example of static prerendering would be an @index.html@ page with some HTML+--+-- @+-- echo "<html><head><//head><body>hello world<//body>" > index.html+-- @+--+-- And a miso application that looks like:+--+-- @+-- main :: IO ()+-- main = prerender defaultEvents $ (vcomp () noop $ \() -> "hello world") { logLevel = DebugPrerender }+-- @+--+-- Assuming the JS / WASM payload and @index.html@ are delivered together from the web server, the console should output below+--+-- > [DEBUG_HYDRATE] Successfully prerendered page+--+-- See the [Haskell miso](https://haskell-miso.org) website console for an example usage of static prerendering with 'miso' and [miso-ui](https://ui.haskell-miso.org) for 'prerender' usage.+--+-- == Dynamic prerendering+--+-- More advanced usage of prerendering entails sharing the @model@ between the server and client. In such scenarios the 'hydateModel' function should be specified inside the t'Component'.+-- The SSR flag (`-fssr`) must be specified when using this feature.+--+-- 'hydrateModel' is used to load initial data into a Component's 'model' that is necessary for hydration.+--+-----------------------------------------------------------------------------+module Miso+ ( -- * API+ -- ** Miso+ miso+ , prerender+ , (🍜)+ -- ** App+ , App+ , startApp+ , renderApp+ -- ** Component+ , Component (..)+ , component+ , vcomp+ , (+>)+ , mount_+ -- ** View+ , vcomp+ , vnode+ , vtext+ -- ** Sink+ , withSink+ , Sink+ -- ** Mail+ , mail+ , checkMail+ , parent+ , mailParent+ , broadcast+ -- ** Subscriptions+ , startSub+ , stopSub+ , Sub+ -- ** Effect+ , issue+ , batch+ , io+ , io_+ , sync+ , sync_+ , for+ -- ** JS file embedding+#ifdef WASM+ , evalFile+#endif+ , withJS+ -- * Bindings+ -- | Primitives for synchronizing parent and child models.+ , module Miso.Binding+ -- * DSL+ -- | A JavaScript DSL for easy FFI interoperability+ , module Miso.DSL+ -- * Effect+ -- | 'Effect', 'Sub', and 'Sink' types for defining update functions and subscriptions.+ , module Miso.Effect+ -- * Event+ -- | Functions for specifying component lifecycle events and event handlers.+ , module Miso.Event+ -- * Fetch+ -- | Interface to the Fetch API for making HTTP requests.+ , module Miso.Fetch+ -- * PubSub+ -- | Publish / Subscribe primitives for communication between components.+ , module Miso.PubSub+ -- * Property+ -- | Construct custom properties on DOM elements.+ , module Miso.Property+ -- * Reload+ -- | Support for clearing the page during live-reloading w/ WASM browser mode.+ , module Miso.Reload+ -- * Subscriptions+ -- | Subscriptions for external events (mouse, keyboard, window, history, etc.).+ , module Miso.Subscription+ -- * Storage+ -- | Web Storage API (Local and Session storage) interface.+ , module Miso.Storage+ -- * Types+ -- | Core types for Miso applications.+ , module Miso.Types+ -- * Util+ -- | Utility functions for views, parsing, and general purpose combinators.+ , module Miso.Util+ -- * FFI+ -- | Foreign Function Interface (FFI) utilities for interacting with JavaScript.+ , module Miso.FFI+ -- * State management+ -- | State management for Miso applications.+ , module Miso.State+ ) where+-----------------------------------------------------------------------------+import Miso.Binding+import Miso.DSL+import Miso.Effect+import Miso.Event+import Miso.Fetch+import Miso.FFI+import qualified Miso.FFI.Internal as FFI+import Miso.Property+import Miso.PubSub+import Miso.Reload+import Miso.Router+import Miso.Runtime+import Miso.State+import Miso.Storage+import Miso.Subscription+import Miso.Types+import Miso.Util+----------------------------------------------------------------------------+-- | Runs an @miso@ application.+--+-- Assumes the pre-rendered DOM is already present.+-- Always mounts to \<body\>. Copies page into the virtual DOM.+--+-- @+-- main :: 'IO' ()+-- main = 'miso' 'defaultEvents' (\\uri -> app uri))+-- @+miso+ :: Eq model+ => Events+ -- ^ Globally delegated Events+ -> (URI -> App model action)+ -- ^ The Component application, with the current URI as an argument+ -> IO ()+miso events f = do+ vcomp_ <- f <$> getURI+ initComponent events Hydrate vcomp_ { mountPoint = Nothing }+----------------------------------------------------------------------------+-- | Like 'miso', except discards the 'URI' argument.+--+-- Use this function if you'd like to prerender, but not use navigation.+--+-- @+-- main :: 'IO' ()+-- main = 'prerender' 'defaultEvents' app+-- @+prerender+ :: Eq model+ => Events+ -- ^ Globally delegated 'Events'+ -> App model action+ -- ^ 'Component' application+ -> IO ()+prerender events comp = initComponent events Hydrate comp { mountPoint = Nothing }+-----------------------------------------------------------------------------+-- | Like 'miso', except it does not perform page hydration.+--+-- This function draws your application on an empty <body>+--+-- You will most likely want to use this function for your application+-- unless you are using prerendering.+--+-- @+-- main :: 'IO' ()+-- main = 'startApp' 'defaultEvents' app+-- @+--+startApp+ :: Eq model+ => Events+ -- ^ Globally delegated 'Events'+ -> App model action+ -- ^ 'Component' application+ -> IO ()+startApp events = initComponent events Draw+-----------------------------------------------------------------------------+-- | Alias for 'Miso.miso'.+(🍜)+ :: Eq model+ => Events+ -- ^ Globally delegated 'Events'+ -> (URI -> App model action)+ -- ^ 'Component' application, with the current URI as an argument+ -> IO ()+(🍜) = miso+----------------------------------------------------------------------------+-- | Runs a 'miso' application, but with a custom rendering engine.+--+-- The 'MisoString' specified here is the variable name of a globally-scoped+-- JS object that implements the context interface per @ts\/miso\/context\/dom.ts@+-- This is necessary for native support.+--+-- It is expected to be run on an empty @\<body\>@+--+-- @+-- main :: IO ()+-- main = 'renderApp' 'defaultEvents' "my-context" app+-- @+renderApp+ :: Eq model+ => Events+ -- ^ Globally delegated 'Events'+ -> MisoString+ -- ^ Name of the JS object that contains the drawing context+ -> App model action+ -- ^ 'Component' application+ -> IO ()+renderApp events renderer comp = do+ FFI.setDrawingContext renderer+ initComponent events Draw comp+----------------------------------------------------------------------------
+ src/Miso/Binding.hs view
@@ -0,0 +1,123 @@+-----------------------------------------------------------------------------+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE RankNTypes #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Binding+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- = Data Bindings+--+-- miso includes an experimental feature that allows fields of different models to be synchronized+-- against each another in response to model changes. See 'Miso.Binding'. Note this feature is+-- experimental, it is recommended to use asynchronous Component communication (like 'broadcast') by default.+--+-- This module exposes combinators to construct a 'Binding' which holds two lenses that will alter+-- t'Component' model state along the parent-child relationship using a 'Lens'. Practically, this means when+-- one t'Component' is marked as dirty, another t'Component' will also potentially will be marked as+-- dirty if they are connected along an edge ('Binding').+--+-- See the [miso-reactive](https://github.com/haskell-miso/miso-reactive) project for more information.+--+----------------------------------------------------------------------------+module Miso.Binding+ ( -- ** Types+ Binding (..)+ -- ** Combinators+ , (<-->)+ , (<--)+ , (-->)+ , (<--->)+ , (<---)+ , (--->)+ ) where+----------------------------------------------------------------------------+import Data.Functor.Const (Const(..))+import Control.Monad.Identity (Identity(..))+----------------------------------------------------------------------------+import Miso.Lens (Lens, Lens', LensCore(..))+----------------------------------------------------------------------------+-- | t'Binding' is used to synchronize parent and child model changes at the granularity specified by a t'Miso.Lens.Lens'+--+-- This can be thought of as establishing an "edge" in the 'Miso.Types.Component' graph,+-- whereby events cause model change synchronization to "ripple" or "pulsate"+-- through the views. The "reactivity" of the graph is constructed manually+-- by the end-user, using the edge primitives `-->`, `<--`, `<-->` (reactive combinators).+--+-- @+-- main :: IO ()+-- main = run app { bindings = [ parentLens \<--\> childLens ] }+-- @+--+-- @since 1.9.0.0+data Binding parent child+ = forall field . ParentToChild (parent -> field) (field -> child -> child)+ | forall field . ChildToParent (field -> parent -> parent) (child -> field)+ | forall field . Bidirectional (parent -> field) (field -> parent -> parent) (child -> field) (field -> child -> child)+-----------------------------------------------------------------------------+-- | Unidirectionally binds a parent field to a child field+--+-- @since 1.9.0.0+infixr 0 -->+(-->) :: Lens parent a -> Lens model a -> Binding parent model+parent --> child = ParentToChild (_get parent) (_set child)+-----------------------------------------------------------------------------+-- | Unidirectionally binds a child field to a parent field+--+-- @since 1.9.0.0+infixl 0 <--+(<--) :: Lens parent a -> Lens model a -> Binding parent model+parent <-- child = ChildToParent (_set parent) (_get child)+-----------------------------------------------------------------------------+-- | Bidirectionally binds a child field to a parent field, using @Lens@+--+-- This is a bidirectional reactive combinator for a miso @Lens@.+--+-- @since 1.9.0.0+infix 0 <-->+(<-->) :: Lens parent field -> Lens child field -> Binding parent child+p <--> c = Bidirectional (_get p) (_set p) (_get c) (_set c)+-----------------------------------------------------------------------------+-- | Bidirectionally binds a child field to a parent field, using @Lens'@+--+-- This is a bidirectional reactive combinator for a van Laarhoven @Lens'@+--+-- @since 1.9.0.0+infix 0 <--->+(<--->) :: Lens' parent field -> Lens' child field -> Binding parent child+p <---> c = Bidirectional (get_ p) (set_ p) (get_ c) (set_ c)+ where+ get_ lens_ record = getConst (lens_ Const record)+ set_ lens_ field = runIdentity . lens_ (\_ -> Identity field)+-----------------------------------------------------------------------------+-- | Unidirectionally binds a parent field to a child field, for van Laarhoven+-- style @Lens'@+--+-- @since 1.9.0.0+infixr 0 --->+(--->) :: Lens' parent field -> Lens' child field -> Binding parent child+p ---> c = ParentToChild (get_ p) (set_ c)+ where+ get_ lens_ record = getConst (lens_ Const record)+ set_ lens_ field = runIdentity . lens_ (\_ -> Identity field)+-----------------------------------------------------------------------------+-- | Unidirectionally binds a child field to a parent field, for van Laarhoven+-- style @Lens'@+--+-- @since 1.9.0.0+infixl 0 <---+(<---) :: Lens' parent field -> Lens' child field -> Binding parent child+p <--- c = ChildToParent (set_ p) (get_ c)+ where+ get_ lens_ record = getConst (lens_ Const record)+ set_ lens_ field = runIdentity . lens_ (\_ -> Identity field)+-----------------------------------------------------------------------------
+ src/Miso/CSS.hs view
@@ -0,0 +1,1424 @@+-----------------------------------------------------------------------------+{-# LANGUAGE OverloadedStrings #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.CSS+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- Module for constructing CSS styles and stylesheets in miso+--+-----------------------------------------------------------------------------+module Miso.CSS+ ( -- *** Types+ module Miso.CSS.Types+ -- *** Smart Constructor+ , style_+ , styleInline_+ , sheet_+ , selector_+ -- *** Render+ , renderStyleSheet+ -- *** Combinators+ , alignContent+ , alignItems+ , alignSelf+ , animationDelay+ , animationDirection+ , animationDuration+ , animationFillMode+ , animationIterationCount+ , animation+ , animationName+ , animationPlayState+ , animationTimingFunction+ , aspectRatio+ , backgroundClip+ , backgroundColor+ , backgroundImage+ , background+ , backgroundOrigin+ , backgroundPosition+ , backgroundRepeat+ , backgroundSize+ , borderBottomColor+ , borderBottomLeftRadius+ , borderBottom+ , borderBottomRightRadius+ , borderBottomStyle+ , borderBottomWidth+ , borderCollapse+ , borderColor+ , borderEndEndRadius+ , borderEndStartRadius+ , borderInlineEndColor+ , borderInlineEndStyle+ , borderInlineEndWidth+ , borderInlineStartColor+ , borderInlineStartStyle+ , borderInlineStartWidth+ , borderLeftColor+ , borderLeft+ , borderLeftStyle+ , borderLeftWidth+ , border+ , borderRadius+ , borderRightColor+ , borderRight+ , borderRightStyle+ , borderRightWidth+ , borderStartEndRadius+ , borderStartStartRadius+ , borderStyle+ , borderTopColor+ , borderTopLeftRadius+ , borderTop+ , borderTopRightRadius+ , borderTopStyle+ , borderTopWidth+ , borderWidth+ , bottom+ , boxShadow+ , boxSizing+ , clipPath+ , color+ , columnGap+ , cssVariable+ , cursor+ , direction+ , display+ , fill+ , filter+ , flexBasis+ , flexDirection+ , flexFlow+ , flexGrow+ , flex+ , flexShrink+ , flexWrap+ , fontFamily+ , fontSize+ , fontStyle+ , fontWeight+ , gap+ , gridAutoColumns+ , gridAutoFlow+ , gridAutoRows+ , gridColumnEnd+ , gridColumnSpan+ , gridColumnStart+ , gridRowEnd+ , gridRowSpan+ , gridRowStart+ , gridTemplateColumns+ , gridTemplateRows+ , height+ , imageRendering+ , insetInlineEnd+ , insetInlineStart+ , justifyContent+ , justifyItems+ , justifySelf+ , left+ , letterSpacing+ , linearCrossGravity+ , linearDirection+ , linearGravity+ , linearLayoutGravity+ , linearWeight+ , linearWeightSum+ , lineHeight+ , marginBottom+ , marginInlineEnd+ , marginInlineStart+ , marginLeft+ , margin+ , marginRight+ , marginTop+ , maskImage+ , mask+ , maxHeight+ , maxWidth+ , minHeight+ , minWidth+ , opacity+ , order+ , overflow+ , overflowX+ , overflowY+ , paddingBottom+ , paddingInlineEnd+ , paddingInlineStart+ , paddingLeft+ , padding+ , paddingRight+ , paddingTop+ , perspective+ , position+ , relativeAlignBottom+ , relativeAlignInlineEnd+ , relativeAlignInlineStart+ , relativeAlignLeft+ , relativeAlignRight+ , relativeAlignTop+ , relativeBottomOf+ , relativeCenter+ , relativeId+ , relativeInlineEndOf+ , relativeInlineStartOf+ , relativeLayoutOnce+ , relativeLeftOf+ , relativeRightOf+ , relativeTopOf+ , right+ , rowGap+ , stroke+ , strokeWidth+ , textAlign+ , textDecoration+ , textIndent+ , textOverflow+ , textShadow+ , textStrokeColor+ , textStroke+ , textStrokeWidth+ , top+ , transform+ , transformOrigin+ , transitionDelay+ , transitionDuration+ , transition+ , transitionProperty+ , transitionTimingFunction+ , verticalAlign+ , visibility+ , whiteSpace+ , width+ , wordBreak+ , xAutoFontSize+ , xAutoFontSizePresetSizes+ , xHandleColor+ , xHandleSize+ , zIndex+ -- *** Colors+ , module Miso.CSS.Color+ -- *** Units+ , px+ , ppx+ , pct+ , pt+ , vw+ , vh+ , deg+ , turn+ , rad+ , rpx+ , rem+ , em+ , s+ , ms+ -- *** Misc+ , url+ , matrix+ -- *** Animation+ , keyframes_+ -- *** Media Queries+ , media_+ ) where+-----------------------------------------------------------------------------+import qualified Data.Map as M+import Miso.String (MisoString)+import qualified Miso.String as MS+import Miso.CSS.Color+import Miso.CSS.Types+import Miso.Property+import Miso.Types (Attribute)+import qualified Miso.Types as MT+import Miso.Util ((=:))+-----------------------------------------------------------------------------+import Prelude hiding (filter, rem)+-----------------------------------------------------------------------------+-- | Font sizing in terms of *pt*+--+-- @+-- >>> pt 10+-- "10pt"+-- @+--+pt :: Int -> MisoString+pt x = MS.ms x <> "pt"+-----------------------------------------------------------------------------+-- | Font sizing in terms of *px*+--+-- @+-- >>> px 10+-- "10px"+-- @+--+px :: Int -> MisoString+px x = MS.ms x <> "px"+-----------------------------------------------------------------------------+-- | Degree specification+--+-- @+-- >>> deg 10+-- "10deg"+-- @+--+deg :: Double -> MisoString+deg x = MS.ms x <> "deg"+-----------------------------------------------------------------------------+-- | Turn constructor, useful for specifying rotations+--+-- @+-- >>> turn 10.0+-- "10.0turn"+-- @+--+turn :: Double -> MisoString+turn x = MS.ms x <> "turn"+-----------------------------------------------------------------------------+-- | Radial constructor+--+-- @+-- >>> rad 10.0+-- "10.0rad"+-- @+--+rad :: Double -> MisoString+rad x = MS.ms x <> "rad"+-----------------------------------------------------------------------------+-- | Responsive pixel sizing, *rpx*+--+-- @+-- >>> rpx 10.0+-- "10.0rpx"+-- @+--+rpx :: Double -> MisoString+rpx x = MS.ms x <> "rpx"+-----------------------------------------------------------------------------+-- | Relative *em* sizing+--+-- @+-- >>> rem 10.0+-- "10.0rem"+-- @+--+rem :: Double -> MisoString+rem x = MS.ms x <> "rem"+-----------------------------------------------------------------------------+-- | *em* sizing+--+-- @+-- >>> em 10.0+-- "10.0em"+-- @+--+em :: Double -> MisoString+em x = MS.ms x <> "em"+-----------------------------------------------------------------------------+-- | Viewport height+--+-- @+-- >>> vh 10.0+-- "10.0vh"+-- @+--+vh :: Double -> MisoString+vh x = MS.ms x <> "vh"+-----------------------------------------------------------------------------+-- | Viewport width+--+-- @+-- >>> vw 10.0+-- "10.0vw"+-- @+--+vw :: Double -> MisoString+vw x = MS.ms x <> "vw"+-----------------------------------------------------------------------------+-- | Duration in seconds+--+-- @+-- >>> s 10.0+-- "10.0s"+-- @+--+s :: Double -> MisoString+s x = MS.ms x <> "s"+-----------------------------------------------------------------------------+-- | Duration in milliseconds+--+-- @+-- >>> ms 10.0+-- "10.0ms"+-- @+--+ms :: Double -> MisoString+ms x = MS.ms x <> "ms"+-----------------------------------------------------------------------------+-- | CSS function for specifying a [URL](https://developer.mozilla.org/en-US/docs/Web/API/StyleSheet)+--+-- @+-- >>> url "dog.png"+-- "url(\"dog.png\")"+-- @+--+url :: MisoString -> MisoString+url x = "url(" <> x <> ")"+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix+matrix+ :: Double+ -> Double+ -> Double+ -> Double+ -> Double+ -> Double+ -> MisoString+matrix a b c d tx ty = "matrix(" <> values <> ")"+ where+ values =+ MS.intercalate ","+ [ MS.ms a+ , MS.ms b+ , MS.ms c+ , MS.ms d+ , MS.ms tx+ , MS.ms ty+ ]+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/percentage+pct :: Double -> MisoString+pct x = MS.ms x <> "%"+-----------------------------------------------------------------------------+-- | ppx unit of measure+ppx :: Double -> MisoString+ppx x = MS.ms x <> "ppx"+-----------------------------------------------------------------------------+-- | Used when constructing a t'StyleSheet'+--+-- @+-- sheet_+-- [ selector_ ".name"+-- [ backgroundColor red+-- , alignContent "top"+-- ]+-- ]+-- @+--+selector_ :: MisoString -> [Style] -> Styles+selector_ k v = Styles (k,v)+-----------------------------------------------------------------------------+-- | Smart constructor for t'StyleSheet'+sheet_ :: [Styles] -> StyleSheet+sheet_ = StyleSheet+-----------------------------------------------------------------------------+-- | @style_@ is an attribute that will set the @style@+-- attribute of the associated DOM node to @attrs@.+--+-- @style@ attributes not contained in @attrs@ will be deleted.+--+-- > div_ [ style_ [ backgroundColor "red" ] [ ]+--+-- <https://developer.mozilla.org/en-US/docs/Web/CSS>+--+style_ :: [Style] -> Attribute action+style_ = MT.Styles . M.fromList+-----------------------------------------------------------------------------+-- | Set "style" property+--+-- > view m = div_ [ styleInline_ "background-color:red;color:blue;" ] [ "foo" ]+--+-- https://developer.mozilla.org/en-US/docs/Web/CSS+styleInline_ :: MisoString -> Attribute action+styleInline_ = textProp "style"+-----------------------------------------------------------------------------+-- | Renders a t'Styles' to a t'MisoString'+renderStyles :: Int -> Styles -> MisoString+renderStyles indent (Styles (sel,styles)) = MS.unlines+ [ sel <> " {" <> MS.replicate indent " "+ , MS.intercalate "\n"+ [ mconcat+ [ MS.replicate (indent + 2) " " <> k+ , " : "+ , v+ , ";"+ ]+ | (k,v) <- styles+ ]+ , MS.replicate indent " " <> "}"+ ]+renderStyles indent (KeyFrame name frames) = MS.intercalate " "+ [ "@keyframes"+ , name+ , "{\n"+ , MS.intercalate "\n "+ [ renderStyles (indent + 2) (Styles frame)+ | frame <- frames+ ]+ , "}\n"+ ]+renderStyles indent (Media name frames) = MS.intercalate " "+ [ "@media"+ , name+ , "{\n"+ , MS.intercalate "\n "+ [ renderStyles (indent + 2) (Styles frame)+ | frame <- frames+ ]+ , "}\n"+ ]+-----------------------------------------------------------------------------+-- | Render t'StyleSheet' as 'MisoString'+--+renderStyleSheet :: StyleSheet -> MisoString+renderStyleSheet styleSheet = MS.intercalate "\n"+ [ renderStyles 0 styles+ | styles <- getStyleSheet styleSheet+ ]+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes+--+-- @+-- testKeyFrame :: Styles+-- testKeyFrame = keyframes "slide-in"+-- [ "from" =:+-- [ transform "translateX(0%)"+-- ]+-- , "to" =:+-- [ transform "translateX(100%)"+-- , backgroundColor red+-- , backgroundSize "10px"+-- , backgroundRepeat "true"+-- ]+-- , pct 10 =:+-- [ "foo" =: "bar"+-- ]+-- ]+-- @+--+keyframes_ :: MisoString -> [(MisoString, [Style])] -> Styles+keyframes_ = KeyFrame+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/@media+--+-- @+-- media_ "screen and (min-width: 480px)"+-- [ "header" =:+-- [ height "auto"+-- ]+-- , "ul" =:+-- [ display "block"+-- ]+-- ]+-- @+--+media_ :: MisoString -> [(MisoString, [Style])] -> Styles+media_ = Media+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/align-content+--+alignContent :: MisoString -> Style+alignContent x = "align-content" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/align-items+--+alignItems :: MisoString -> Style+alignItems x = "align-items" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/align-self+--+alignSelf :: MisoString -> Style+alignSelf x = "align-self" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation-delay+--+animationDelay :: MisoString -> Style+animationDelay x = "animation-delay" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation-direction+--+animationDirection :: MisoString -> Style+animationDirection x = "animation-direction" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation-duration+--+animationDuration :: MisoString -> Style+animationDuration x = "animation-duration" =: x+-----------------------------------------------------------------------------+-- | https://animation-mozilla.org/en-US/docs/Web/CSS/align-content/animation-fill-mode+--+animationFillMode :: MisoString -> Style+animationFillMode x = "animation-fill-mode" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation-iteration-count+--+animationIterationCount :: MisoString -> Style+animationIterationCount x = "animation-iteration-count" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation+--+animation :: MisoString -> Style+animation x = "animation" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation-name+--+animationName :: MisoString -> Style+animationName x = "animation-name" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation-play-state+-- > style_ [ animationPlayState =: "value" ]+--+animationPlayState :: MisoString -> Style+animationPlayState x = "animation-play-state" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function+--+animationTimingFunction :: MisoString -> Style+animationTimingFunction x = "animation-timing-function" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio+--+aspectRatio :: MisoString -> Style+aspectRatio x = "aspect-ratio" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background-clip+--+backgroundClip :: MisoString -> Style+backgroundClip x = "background-clip" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background-color+--+backgroundColor :: Color -> Style+backgroundColor x = "background-color" =: renderColor x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background-image+--+backgroundImage :: MisoString -> Style+backgroundImage x = "background-image" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background+--+background :: MisoString -> Style+background x = "background" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background-origin+--+backgroundOrigin :: MisoString -> Style+backgroundOrigin x = "background-origin" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background-position+--+backgroundPosition :: MisoString -> Style+backgroundPosition x = "background-position" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background-repeat+--+backgroundRepeat :: MisoString -> Style+backgroundRepeat x = "background-repeat" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/background-size+--+backgroundSize :: MisoString -> Style+backgroundSize x = "background-size" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-color+--+borderBottomColor :: Color -> Style+borderBottomColor x = "border-bottom-color" =: renderColor x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-left-radius+--+borderBottomLeftRadius :: MisoString -> Style+borderBottomLeftRadius x = "border-bottom-left-radius" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom+--+borderBottom :: MisoString -> Style+borderBottom x = "border-bottom" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-right-radius+--+borderBottomRightRadius :: MisoString -> Style+borderBottomRightRadius x = "border-bottom-right-radius" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-style+--+borderBottomStyle :: MisoString -> Style+borderBottomStyle x = "border-bottom-style" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-bottom-width+--+borderBottomWidth :: MisoString -> Style+borderBottomWidth x = "border-bottom-width" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-collapse+--+borderCollapse :: MisoString -> Style+borderCollapse x = "border-collapse" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-color+--+borderColor :: Color -> Style+borderColor x = "border-color" =: renderColor x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-end-radius+--+borderEndEndRadius :: MisoString -> Style+borderEndEndRadius x = "border-end-end-radius" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-end-start-radius+--+borderEndStartRadius :: MisoString -> Style+borderEndStartRadius x = "border-end-start-radius" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-inline-end-color+--+borderInlineEndColor :: Color -> Style+borderInlineEndColor x = "border-inline-end-color" =: renderColor x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-inline-end-style+--+borderInlineEndStyle :: MisoString -> Style+borderInlineEndStyle x = "border-inline-end-style" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-inline-end-width+--+borderInlineEndWidth :: MisoString -> Style+borderInlineEndWidth x = "border-inline-end-width" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-inline-start-color+--+borderInlineStartColor :: Color -> Style+borderInlineStartColor x = "border-inline-start-color" =: renderColor x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-inline-start-style+--+borderInlineStartStyle :: MisoString -> Style+borderInlineStartStyle x = "border-inline-start-style" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-inline-start-width+--+borderInlineStartWidth :: MisoString -> Style+borderInlineStartWidth x = "border-inline-start-width" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-left-color+--+borderLeftColor :: Color -> Style+borderLeftColor x = "border-left-color" =: renderColor x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-left+--+borderLeft :: MisoString -> Style+borderLeft x = "border-left" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-left-style+--+borderLeftStyle :: MisoString -> Style+borderLeftStyle x = "border-left-style" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-left-width+--+borderLeftWidth :: MisoString -> Style+borderLeftWidth x = "border-left-width" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border+--+border :: MisoString -> Style+border x = "border" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius+--+borderRadius :: MisoString -> Style+borderRadius x = "border-radius" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-right-color+--+borderRightColor :: Color -> Style+borderRightColor x = "border-right-color" =: renderColor x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-right+--+borderRight :: MisoString -> Style+borderRight x = "border-right" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-right-style+--+borderRightStyle :: MisoString -> Style+borderRightStyle x = "border-right-style" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-right-width+--+borderRightWidth :: MisoString -> Style+borderRightWidth x = "border-right-width" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-start-end-radius+--+borderStartEndRadius :: MisoString -> Style+borderStartEndRadius x = "border-start-end-radius" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-start-start-radius+--+borderStartStartRadius :: MisoString -> Style+borderStartStartRadius x = "border-start-start-radius" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-style+--+borderStyle :: MisoString -> Style+borderStyle x = "border-style" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-top-color+--+borderTopColor :: Color -> Style+borderTopColor x = "border-top-color" =: renderColor x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-top-left-radius+--+borderTopLeftRadius :: MisoString -> Style+borderTopLeftRadius x = "border-top-left-radius" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-top+--+borderTop :: MisoString -> Style+borderTop x = "border-top" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-top-right-radius+--+borderTopRightRadius :: MisoString -> Style+borderTopRightRadius x = "border-top-right-radius" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-top-style+--+borderTopStyle :: MisoString -> Style+borderTopStyle x = "border-top-style" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-top-width+--+borderTopWidth :: MisoString -> Style+borderTopWidth x = "border-top-width" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/border-width+--+borderWidth :: MisoString -> Style+borderWidth x = "border-width" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/bottom+--+bottom :: MisoString -> Style+bottom x = "bottom" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow+--+boxShadow :: MisoString -> Style+boxShadow x = "box-shadow" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing+--+boxSizing :: MisoString -> Style+boxSizing x = "box-sizing" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path+--+clipPath :: MisoString -> Style+clipPath x = "clip-path" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/color+--+color :: Color -> Style+color x = "color" =: renderColor x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/column-gap+--+columnGap :: MisoString -> Style+columnGap x = "column-gap" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/css-variable+--+cssVariable :: MisoString -> Style+cssVariable x = "css-variable" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/direction+--+direction :: MisoString -> Style+direction x = "direction" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/display+--+display :: MisoString -> Style+display x = "display" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/fill+--+fill :: MisoString -> Style+fill x = "fill" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/filter+--+filter :: MisoString -> Style+filter x = "filter" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis+--+flexBasis :: MisoString -> Style+flexBasis x = "flex-basis" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction+--+flexDirection :: MisoString -> Style+flexDirection x = "flex-direction" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/flex-flow+--+flexFlow :: MisoString -> Style+flexFlow x = "flex-flow" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/flex-grow+--+flexGrow :: MisoString -> Style+flexGrow x = "flex-grow" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/flex+--+flex :: MisoString -> Style+flex x = "flex" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/flex-shrink+--+flexShrink :: MisoString -> Style+flexShrink x = "flex-shrink" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap+--+flexWrap :: MisoString -> Style+flexWrap x = "flex-wrap" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/font-family+--+fontFamily :: MisoString -> Style+fontFamily x = "font-family" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/font-size+--+fontSize :: MisoString -> Style+fontSize x = "font-size" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/font-style+--+fontStyle :: MisoString -> Style+fontStyle x = "font-style" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight+--+fontWeight :: MisoString -> Style+fontWeight x = "font-weight" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/cursor+--+cursor :: MisoString -> Style+cursor x = "cursor" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/gap+--+gap :: MisoString -> Style+gap x = "gap" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-columns+--+gridAutoColumns :: MisoString -> Style+gridAutoColumns x = "grid-auto-columns" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow+--+gridAutoFlow :: MisoString -> Style+gridAutoFlow x = "grid-auto-flow" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-rows+--+gridAutoRows :: MisoString -> Style+gridAutoRows x = "grid-auto-rows" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column-end+--+gridColumnEnd :: MisoString -> Style+gridColumnEnd x = "grid-column-end" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column-span+--+gridColumnSpan :: MisoString -> Style+gridColumnSpan x = "grid-column-span" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column-start+--+gridColumnStart :: MisoString -> Style+gridColumnStart x = "grid-column-start" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row-end+--+gridRowEnd :: MisoString -> Style+gridRowEnd x = "grid-row-end" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row-span+--+gridRowSpan :: MisoString -> Style+gridRowSpan x = "grid-row-span" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row-start+--+gridRowStart :: MisoString -> Style+gridRowStart x = "grid-row-start" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns+--+gridTemplateColumns :: MisoString -> Style+gridTemplateColumns x = "grid-template-columns" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-rows+--+gridTemplateRows :: MisoString -> Style+gridTemplateRows x = "grid-template-rows" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/height+--+height :: MisoString -> Style+height x = "height" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/image-rendering+--+imageRendering :: MisoString -> Style+imageRendering x = "image-rendering" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/inset-inline-end+--+insetInlineEnd :: MisoString -> Style+insetInlineEnd x = "inset-inline-end" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/inset-inline-start+--+insetInlineStart :: MisoString -> Style+insetInlineStart x = "inset-inline-start" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content+--+justifyContent :: MisoString -> Style+justifyContent x = "justify-content" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/justify-items+--+justifyItems :: MisoString -> Style+justifyItems x = "justify-items" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/justify-self+--+justifySelf :: MisoString -> Style+justifySelf x = "justify-self" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/left+--+left :: MisoString -> Style+left x = "left" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/letter-spacing+--+letterSpacing :: MisoString -> Style+letterSpacing x = "letter-spacing" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/linear-cross-gravity+--+linearCrossGravity :: MisoString -> Style+linearCrossGravity x = "linear-cross-gravity" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/linear-direction+--+linearDirection :: MisoString -> Style+linearDirection x = "linear-direction" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gravity+--+linearGravity :: MisoString -> Style+linearGravity x = "linear-gravity" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/linear-layout-gravity+--+linearLayoutGravity :: MisoString -> Style+linearLayoutGravity x = "linear-layout-gravity" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/linear-weight+--+linearWeight :: MisoString -> Style+linearWeight x = "linear-weight" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/linear-weight-sum+--+linearWeightSum :: MisoString -> Style+linearWeightSum x = "linear-weight-sum" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/line-height+--+lineHeight :: MisoString -> Style+lineHeight x = "line-height" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/margin-bottom+--+marginBottom :: MisoString -> Style+marginBottom x = "margin-bottom" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/margin-inline-end+--+marginInlineEnd :: MisoString -> Style+marginInlineEnd x = "margin-inline-end" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/margin-inline-start+--+marginInlineStart :: MisoString -> Style+marginInlineStart x = "margin-inline-start" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/margin-left+--+marginLeft :: MisoString -> Style+marginLeft x = "margin-left" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/margin+--+margin :: MisoString -> Style+margin x = "margin" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/margin-right+--+marginRight :: MisoString -> Style+marginRight x = "margin-right" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/margin-top+--+marginTop :: MisoString -> Style+marginTop x = "margin-top" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/mask-image+--+maskImage :: MisoString -> Style+maskImage x = "mask-image" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/mask+--+mask :: MisoString -> Style+mask x = "mask" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/max-height+--+maxHeight :: MisoString -> Style+maxHeight x = "max-height" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/max-width+--+maxWidth :: MisoString -> Style+maxWidth x = "max-width" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/min-height+--+minHeight :: MisoString -> Style+minHeight x = "min-height" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/min-width+--+minWidth :: MisoString -> Style+minWidth x = "min-width" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/opacity+--+opacity :: MisoString -> Style+opacity x = "opacity" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/order+--+order :: MisoString -> Style+order x = "order" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/overflow+--+overflow :: MisoString -> Style+overflow x = "overflow" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-x+--+overflowX :: MisoString -> Style+overflowX x = "overflow-x" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-y+--+overflowY :: MisoString -> Style+overflowY x = "overflow-y" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/padding-bottom+--+paddingBottom :: MisoString -> Style+paddingBottom x = "padding-bottom" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/padding-inline-end+--+paddingInlineEnd :: MisoString -> Style+paddingInlineEnd x = "padding-inline-end" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/padding-inline-start+--+paddingInlineStart :: MisoString -> Style+paddingInlineStart x = "padding-inline-start" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/padding-left+--+paddingLeft :: MisoString -> Style+paddingLeft x = "padding-left" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/padding+--+padding :: MisoString -> Style+padding x = "padding" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/padding-right+--+paddingRight :: MisoString -> Style+paddingRight x = "padding-right" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/padding-top+--+paddingTop :: MisoString -> Style+paddingTop x = "padding-top" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/perspective+--+perspective :: MisoString -> Style+perspective x = "perspective" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/position+--+position :: MisoString -> Style+position x = "position" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-align-bottom+--+relativeAlignBottom :: MisoString -> Style+relativeAlignBottom x = "relative-align-bottom" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-align-inline-end+--+relativeAlignInlineEnd :: MisoString -> Style+relativeAlignInlineEnd x = "relative-align-inline-end" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-align-inline-start+--+relativeAlignInlineStart :: MisoString -> Style+relativeAlignInlineStart x = "relative-align-inline-start" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-align-left+--+relativeAlignLeft :: MisoString -> Style+relativeAlignLeft x = "relative-align-left" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-align-right+--+relativeAlignRight :: MisoString -> Style+relativeAlignRight x = "relative-align-right" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-align-top+--+relativeAlignTop :: MisoString -> Style+relativeAlignTop x = "relative-align-top" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-bottom-of+--+relativeBottomOf :: MisoString -> Style+relativeBottomOf x = "relative-bottom-of" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-center+--+relativeCenter :: MisoString -> Style+relativeCenter x = "relative-center" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-id+--+relativeId :: MisoString -> Style+relativeId x = "relative-id" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-inline-end-of+--+relativeInlineEndOf :: MisoString -> Style+relativeInlineEndOf x = "relative-inline-end-of" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-inline-start-of+--+relativeInlineStartOf :: MisoString -> Style+relativeInlineStartOf x = "relative-inline-start-of" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-layout-once+--+relativeLayoutOnce :: MisoString -> Style+relativeLayoutOnce x = "relative-layout-once" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-left-of+--+relativeLeftOf :: MisoString -> Style+relativeLeftOf x = "relative-left-of" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-right-of+--+relativeRightOf :: MisoString -> Style+relativeRightOf x = "relative-right-of" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/relative-top-of+--+relativeTopOf :: MisoString -> Style+relativeTopOf x = "relative-top-of" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/right+--+right :: MisoString -> Style+right x = "right" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/row-gap+--+rowGap :: MisoString -> Style+rowGap x = "row-gap" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/stroke+--+stroke :: MisoString -> Style+stroke x = "stroke" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/stroke-width+--+strokeWidth :: MisoString -> Style+strokeWidth x = "stroke-width" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-align+--+textAlign :: MisoString -> Style+textAlign x = "text-align" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration+--+textDecoration :: MisoString -> Style+textDecoration x = "text-decoration" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-indent+--+textIndent :: MisoString -> Style+textIndent x = "text-indent" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-overflow+--+textOverflow :: MisoString -> Style+textOverflow x = "text-overflow" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow+--+textShadow :: MisoString -> Style+textShadow x = "text-shadow" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-stroke-color+--+textStrokeColor :: Color -> Style+textStrokeColor x = "text-stroke-color" =: renderColor x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-stroke+--+textStroke :: MisoString -> Style+textStroke x = "text-stroke" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/text-stroke-width+--+textStrokeWidth :: MisoString -> Style+textStrokeWidth x = "text-stroke-width" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/top+--+top :: MisoString -> Style+top x = "top" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform+--+transform :: MisoString -> Style+transform x = "transform" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin+--+transformOrigin :: MisoString -> Style+transformOrigin x = "transform-origin" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transition-delay+--+transitionDelay :: MisoString -> Style+transitionDelay x = "transition-delay" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transition-duration+--+transitionDuration :: MisoString -> Style+transitionDuration x = "transition-duration" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transition+--+transition :: MisoString -> Style+transition x = "transition" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transition-property+--+transitionProperty :: MisoString -> Style+transitionProperty x = "transition-property" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/transition-timing-function+--+transitionTimingFunction :: MisoString -> Style+transitionTimingFunction x = "transition-timing-function" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align+--+verticalAlign :: MisoString -> Style+verticalAlign x = "vertical-align" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/visibility+--+visibility :: MisoString -> Style+visibility x = "visibility" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/white-space+--+whiteSpace :: MisoString -> Style+whiteSpace x = "white-space" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/width+--+width :: MisoString -> Style+width x = "width" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/word-break+--+wordBreak :: MisoString -> Style+wordBreak x = "word-break" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/xAutoFontSize+--+xAutoFontSize :: MisoString -> Style+xAutoFontSize x = "-x-auto-font-size" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/xAutoFontSizePresetSizes+--+xAutoFontSizePresetSizes :: MisoString -> Style+xAutoFontSizePresetSizes x = "-x-auto-font-size-preset-sizes" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/xHandleColor+--+xHandleColor :: Color -> Style+xHandleColor x = "-x-handle-color" =: renderColor x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/xHandleSize+--+xHandleSize :: MisoString -> Style+xHandleSize x = "-x-handle-size" =: x+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/CSS/z-index+--+zIndex :: MisoString -> Style+zIndex x = "z-index" =: x+-----------------------------------------------------------------------------
+ src/Miso/CSS/Color.hs view
@@ -0,0 +1,1836 @@+-----------------------------------------------------------------------------+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}+-----------------------------------------------------------------------------+{-# OPTIONS_GHC -fno-warn-orphans #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.CSS.Color+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+-----------------------------------------------------------------------------+module Miso.CSS.Color+ ( -- *** Types+ Color (RGB, RGBA, HSL, HSLA, OKLCH, OKLCHA, Hex)+ -- *** Smart constructor+ , rgba+ , rgb+ , hsl+ , hsla+ , oklch+ , oklcha+ , hex+ , var+ -- *** Render+ , renderColor+ -- *** Colors+ , transparent+ , aliceblue+ , antiquewhite+ , aqua+ , aquamarine+ , azure+ , beige+ , bisque+ , black+ , blanchedalmond+ , blue+ , blueviolet+ , brown+ , burlywood+ , cadetblue+ , chartreuse+ , chocolate+ , coral+ , cornflowerblue+ , cornsilk+ , crimson+ , cyan+ , darkblue+ , darkcyan+ , darkgoldenrod+ , darkgray+ , darkgreen+ , darkgrey+ , darkkhaki+ , darkmagenta+ , darkolivegreen+ , darkorange+ , darkorchid+ , darkred+ , darksalmon+ , darkseagreen+ , darkslateblue+ , darkslategray+ , darkslategrey+ , darkturquoise+ , darkviolet+ , deeppink+ , deepskyblue+ , dimgray+ , dimgrey+ , dodgerblue+ , firebrick+ , floralwhite+ , forestgreen+ , fuchsia+ , gainsboro+ , ghostwhite+ , gold+ , goldenrod+ , gray+ , green+ , greenyellow+ , grey+ , honeydew+ , hotpink+ , indianred+ , indigo+ , ivory+ , khaki+ , lavender+ , lavenderblush+ , lawngreen+ , lemonchiffon+ , lightblue+ , lightcoral+ , lightcyan+ , lightgoldenrodyellow+ , lightgray+ , lightgreen+ , lightgrey+ , lightpink+ , lightsalmon+ , lightseagreen+ , lightskyblue+ , lightslategray+ , lightslategrey+ , lightsteelblue+ , lightyellow+ , lime+ , limegreen+ , linen+ , magenta+ , maroon+ , mediumaquamarine+ , mediumblue+ , mediumorchid+ , mediumpurple+ , mediumseagreen+ , mediumslateblue+ , mediumspringgreen+ , mediumturquoise+ , mediumvioletred+ , midnightblue+ , mintcream+ , mistyrose+ , moccasin+ , navajowhite+ , navy+ , oldlace+ , olive+ , olivedrab+ , orange+ , orangered+ , orchid+ , palegoldenrod+ , palegreen+ , paleturquoise+ , palevioletred+ , papayawhip+ , peachpuff+ , peru+ , pink+ , plum+ , powderblue+ , purple+ , red+ , rosybrown+ , royalblue+ , saddlebrown+ , salmon+ , sandybrown+ , seagreen+ , seashell+ , sienna+ , silver+ , skyblue+ , slateblue+ , slategray+ , slategrey+ , snow+ , springgreen+ , steelblue+ , tan+ , teal+ , thistle+ , tomato+ , turquoise+ , violet+ , wheat+ , white+ , whitesmoke+ , yellow+ , yellowgreen+ ) where+-----------------------------------------------------------------------------+import Miso.String (MisoString, ms)+import qualified Miso.String as MS+-----------------------------------------------------------------------------+import Data.Proxy+import GHC.TypeLits+import GHC.OverloadedLabels+import Miso.DSL (ToJSVal(..), ToArgs(..))+import Prelude hiding (tan)+-----------------------------------------------------------------------------+-- | Data type for expressing Color+data Color+ = RGBA Int Int Int Double+ -- ^ Red, green, blue and alpha transparency. See [here](https://www.w3schools.com/colors/colors_rgb.asp)+ | RGB Int Int Int+ -- ^ Red, green, blue. See [here](https://www.w3schools.com/colors/colors_rgb.asp)+ | HSL Int Int Int+ -- ^ Hue, saturation, light. See [here](https://www.w3schools.com/colors/colors_hsl.asp)+ | HSLA Int Int Int Double+ -- ^ Hue, saturation, light and alpha transparency. See [here](https://www.w3schools.com/colors/colors_hsl.asp)+ | Hex MisoString+ -- ^ Hexadecimal representation of a color. See [here](https://www.w3schools.com/colors/colors_hexadecimal.asp)+ | VarColor MisoString+ -- ^ A CSS variable+ | OKLCH Double Double Double+ -- ^ Lightness, Chroma, Hue. See [oklch](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/oklch).+ | OKLCHA Double Double Double Double+ -- ^ Lightness, Chroma, Hue, Alpha. See [oklhc](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/oklch).+ deriving (Show, Eq)+-----------------------------------------------------------------------------+-- | 'IsLabel' instance on 'Color'+--+-- @+-- grey :: Color+-- grey = #cccccc+-- @+instance KnownSymbol color => IsLabel color Color where+ fromLabel = Hex (ms color)+ where+ color = symbolVal (Proxy @color)+-----------------------------------------------------------------------------+-- | 'IsLabel' instance on 'MisoString' for construction of hex colors as strings+--+-- @+-- grey :: MisoString+-- grey = #cccccc+-- @+instance KnownSymbol hex => IsLabel hex MisoString where+ fromLabel = ms ("#" <> symbolVal (Proxy @hex))+-----------------------------------------------------------------------------+-- | 'ToArgs' instance for 'Color'+instance ToArgs Color where+ toArgs color = (:[]) <$> toJSVal color+-----------------------------------------------------------------------------+-- | 'ToJSVal' instance for 'Color'+instance ToJSVal Color where+ toJSVal = toJSVal . renderColor+-----------------------------------------------------------------------------+-- | Renders a 'Color' as 'MisoString'+--+-- >>> renderColor (hex "ccc")+-- "#ccc"+--+renderColor :: Color -> MisoString+renderColor (RGBA r g b a) = "rgba(" <> values <> ")"+ where+ values = MS.intercalate ","+ [ MS.ms r+ , MS.ms g+ , MS.ms b+ , MS.ms a+ ]+renderColor (RGB r g b) = "rgb(" <> values <> ")"+ where+ values = MS.intercalate ","+ [ MS.ms r+ , MS.ms g+ , MS.ms b+ ]+renderColor (HSLA h s l a) = "hsla(" <> values <> ")"+ where+ values = MS.intercalate ","+ [ MS.ms h+ , MS.ms s+ , MS.ms l+ , MS.ms a+ ]+renderColor (HSL h s l) = "hsl(" <> values <> ")"+ where+ values = MS.intercalate ","+ [ MS.ms h+ , MS.ms s+ , MS.ms l+ ]+renderColor (OKLCH l c h) = "oklch(" <> values <> ")"+ where+ values = MS.intercalate " "+ [ MS.ms l <> "%"+ , MS.ms c+ , MS.ms h+ ]+renderColor (OKLCHA l c h a) = "oklch(" <> values <> ")"+ where+ values = MS.intercalate " "+ [ MS.ms l <> "%"+ , MS.ms c+ , MS.ms h+ ] <> " / " <> MS.ms a+renderColor (Hex s) = "#" <> s+renderColor (VarColor n) = "var(--" <> n <> ")"+-----------------------------------------------------------------------------+-- | Smart constructor for a [CSS variable](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_cascading_variables/Using_CSS_custom_properties).+--+-- >>> renderColor (var "foo")+-- "var(--foo)"+--+var :: MisoString -> Color+var = VarColor+-----------------------------------------------------------------------------+-- | Smart constructor for an [RGBA](https://www.w3schools.com/css/css_colors_rgb.asp) 'Color' value.+--+-- >>> renderColor (rgba 0 0 0 1.0)+-- "rgba(0,0,0,1.0)"+--+rgba :: Int -> Int -> Int -> Double -> Color+rgba = RGBA+-----------------------------------------------------------------------------+-- | Smart constructor for an [RGB](https://www.w3schools.com/css/css_colors_rgb.asp) 'Color' value.+--+-- >>> renderColor (rgb 0 0 0)+-- "rgb(0,0,0)"+--+rgb :: Int -> Int -> Int -> Color+rgb = RGB+-----------------------------------------------------------------------------+-- | Smart constructor for an [HSL](https://www.w3schools.com/css/css_colors_hsl.asp) 'Color' value.+--+-- >>> renderColor (hsl 0 0 0)+-- "hsl(0,0,0)"+--+hsl :: Int -> Int -> Int -> Color+hsl = HSL+-----------------------------------------------------------------------------+-- | Smart constructor for a [HSLA](https://www.w3schools.com/css/css_colors_hsl.asp) 'Color' value.+--+-- >>> renderColor (hsla 0 0 0 1.0)+-- "hsla(0,0,0,1.0)"+--+hsla :: Int -> Int -> Int -> Double -> Color+hsla = HSLA+-----------------------------------------------------------------------------+-- | Smart constructor for a 'Hex' 'Color'+--+-- >>> renderColor (hsla 0 0 0 1.0)+-- "hsl(0,0,0,1.0)"+--+hex :: MisoString -> Color+hex = Hex+-----------------------------------------------------------------------------+-- | Smart constructor for an 'OKLCH' 'Color'+--+-- >>> renderColor (oklch 40.1 0.123 0.123)+-- "oklch(40.1% 0.123 0.123)"+--+oklch :: Double -> Double -> Double -> Color+oklch = OKLCH+-----------------------------------------------------------------------------+-- | Smart constructor for an 'OKLCH' 'Color' with alpha transparency+--+-- >>> renderColor (oklcha 40.1 0.123 0.123 0.5)+-- "oklcha(40.1% 0.123 0.123 / 0.5)"+--+oklcha :: Double -> Double -> Double -> Double -> Color+oklcha = OKLCHA+-----------------------------------------------------------------------------+-- | Smart constructor for the 'transparent' color+--+-- >>> renderColor transparent+-- "rgba(0,0,0,0.0)"+--+transparent :: Color+transparent = rgba 0 0 0 0+-- <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><rect width="100" height="100" fill="goldenrod"/></svg>+-- data:image/svg+xml;base64,+-----------------------------------------------------------------------------+-- | Smart constructor for the 'aliceblue' 'Color'.+--+-- >>> renderColor aliceblue+-- "rgba(240,248,255,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYWxpY2VibHVlIi8+PC9zdmc+>>+--+aliceblue :: Color+aliceblue = rgba 240 248 255 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'antiquewhite' 'Color'.+--+-- >>> renderColor antiquewhite+-- "rgba(250,235,215,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYW50aXF1ZXdoaXRlIi8+PC9zdmc+>>+--+antiquewhite :: Color+antiquewhite = rgba 250 235 215 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'aqua' 'Color'.+--+-- >>> renderColor aqua+-- "rgba(0,255,255,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYXF1YSIvPjwvc3ZnPg==>>+--+aqua :: Color+aqua = rgba 0 255 255 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'aquamarine' 'Color'.+--+-- >>> renderColor aquamarine+-- "rgba(127,255,212,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYXF1YW1hcmluZSIvPjwvc3ZnPg==>>+--+aquamarine :: Color+aquamarine = rgba 127 255 212 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'azure' 'Color'.+--+-- >>> renderColor azure+-- "rgba(240,255,255,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYXp1cmUiLz48L3N2Zz4=>>+--+azure :: Color+azure = rgba 240 255 255 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'beige' 'Color'.+--+-- >>> renderColor beige+-- "rgba(245,245,220,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYmVpZ2UiLz48L3N2Zz4=>>+--+beige :: Color+beige = rgba 245 245 220 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'bisque' 'Color'.+--+-- >>> renderColor bisque+-- "rgba(255,228,196,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYmlzcXVlIi8+PC9zdmc+>>+--+bisque :: Color+bisque = rgba 255 228 196 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'black' 'Color'.+--+-- >>> renderColor black+-- "rgba(0,0,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYmxhY2siLz48L3N2Zz4=>>+--+black :: Color+black = rgba 0 0 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'blanchedalmond' 'Color'.+--+-- >>> renderColor blanchedalmond+-- "rgba(255,235,205,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYmxhbmNoZWRhbG1vbmQiLz48L3N2Zz4=>>+--+blanchedalmond :: Color+blanchedalmond = rgba 255 235 205 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'blue' 'Color'.+--+-- >>> renderColor blue+-- "rgba(0,0,255,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYmx1ZSIvPjwvc3ZnPg==>>+--+blue :: Color+blue = rgba 0 0 255 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'blueviolet' 'Color'.+--+-- >>> renderColor blueviolet+-- "rgba(138,43,226,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYmx1ZXZpb2xldCIvPjwvc3ZnPg==>>+--+blueviolet :: Color+blueviolet = rgba 138 43 226 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'brown' 'Color'.+--+-- >>> renderColor brown+-- "rgba(165,42,42,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYnJvd24iLz48L3N2Zz4=>>+--+brown :: Color+brown = rgba 165 42 42 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'burlywood' 'Color'.+--+-- >>> renderColor burlywood+-- "rgba(222,184,135,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iYnVybHl3b29kIi8+PC9zdmc+>>+--+burlywood :: Color+burlywood = rgba 222 184 135 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'cadetblue' 'Color'.+--+-- >>> renderColor cadetblue+-- "rgba(95,158,160,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY2FkZXRibHVlIi8+PC9zdmc+>>+--+cadetblue :: Color+cadetblue = rgba 95 158 160 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'chartreuse' 'Color'.+--+-- >>> renderColor chartreuse+-- "rgba(127,255,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY2hhcnRyZXVzZSIvPjwvc3ZnPg==>>+--+chartreuse :: Color+chartreuse = rgba 127 255 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'chocolate' 'Color'.+--+-- >>> renderColor chocolate+-- "rgba(210,105,30,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY2hvY29sYXRlIi8+PC9zdmc+>>+--+chocolate :: Color+chocolate = rgba 210 105 30 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'coral' 'Color'.+--+-- >>> renderColor coral+-- "rgba(255,127,80,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY29yYWwiLz48L3N2Zz4=>>+--+coral :: Color+coral = rgba 255 127 80 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'cornflowerblue' 'Color'.+--+-- >>> renderColor cornflowerblue+-- "rgba(100,149,237,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY29ybmZsb3dlcmJsdWUiLz48L3N2Zz4=>>+--+cornflowerblue :: Color+cornflowerblue = rgba 100 149 237 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'cornsilk' 'Color'.+--+-- >>> renderColor cornsilk+-- "rgba(255,248,220,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY29ybnNpbGsiLz48L3N2Zz4=>>+--+cornsilk :: Color+cornsilk = rgba 255 248 220 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'crimson' 'Color'.+--+-- >>> renderColor crimson+-- "rgba(220,20,60,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY3JpbXNvbiIvPjwvc3ZnPg==>>+--+crimson :: Color+crimson = rgba 220 20 60 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'cyan' 'Color'.+--+-- >>> renderColor cyan+-- "rgba(0,255,255,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iY3lhbiIvPjwvc3ZnPg==>>+--+cyan :: Color+cyan = rgba 0 255 255 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkblue' 'Color'.+--+-- >>> renderColor darkblue+-- "rgba(0,0,139,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya2JsdWUiLz48L3N2Zz4=>>+--+darkblue :: Color+darkblue = rgba 0 0 139 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkcyan' 'Color'.+--+-- >>> renderColor darkcyan+-- "rgba(0,139,139,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya2N5YW4iLz48L3N2Zz4=>>+--+darkcyan :: Color+darkcyan = rgba 0 139 139 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkgoldenrod' 'Color'.+--+-- >>> renderColor darkgoldenrod+-- "rgba(184,134,11,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya2dvbGRlbnJvZCIvPjwvc3ZnPg==>>+--+darkgoldenrod :: Color+darkgoldenrod = rgba 184 134 11 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkgray' 'Color'.+--+-- >>> renderColor darkgray+-- "rgba(169,169,169,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya2dyYXkiLz48L3N2Zz4=>>+--+darkgray :: Color+darkgray = rgba 169 169 169 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkgreen' 'Color'.+--+-- >>> renderColor darkgreen+-- "rgba(0,100,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya2dyZWVuIi8+PC9zdmc+>>+--+darkgreen :: Color+darkgreen = rgba 0 100 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkgrey' 'Color'.+--+-- >>> renderColor darkgrey+-- "rgba(169,169,169,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya2dyZXkiLz48L3N2Zz4=>>+--+darkgrey :: Color+darkgrey = rgba 169 169 169 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkkhaki' 'Color'.+--+-- >>> renderColor darkkhaki+-- "rgba(189,183,107,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya2toYWtpIi8+PC9zdmc+>>+--+darkkhaki :: Color+darkkhaki = rgba 189 183 107 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkmagenta' 'Color'.+--+-- >>> renderColor darkmagenta+-- "rgba(139,0,139,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya21hZ2VudGEiLz48L3N2Zz4=>>+--+darkmagenta :: Color+darkmagenta = rgba 139 0 139 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkolivegreen' 'Color'.+--+-- >>> renderColor darkolivegreen+-- "rgba(85,107,47,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya29saXZlZ3JlZW4iLz48L3N2Zz4=>>+--+darkolivegreen :: Color+darkolivegreen = rgba 85 107 47 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkorange' 'Color'.+--+-- >>> renderColor darkorange+-- "rgba(255,140,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya29yYW5nZSIvPjwvc3ZnPg==>>+--+darkorange :: Color+darkorange = rgba 255 140 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkorchid' 'Color'.+--+-- >>> renderColor darkorchid+-- "rgba(153,50,204,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya29yY2hpZCIvPjwvc3ZnPg==>>+--+darkorchid :: Color+darkorchid = rgba 153 50 204 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkred' 'Color'.+--+-- >>> renderColor darkred+-- "rgba(139,0,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3JlZCIvPjwvc3ZnPg==>>+--+darkred :: Color+darkred = rgba 139 0 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darksalmon' 'Color'.+--+-- >>> renderColor darksalmon+-- "rgba(233,150,122,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3NhbG1vbiIvPjwvc3ZnPg==>>+--+darksalmon :: Color+darksalmon = rgba 233 150 122 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkseagreen' 'Color'.+--+-- >>> renderColor darkseagreen+-- "rgba(143,188,143,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3NlYWdyZWVuIi8+PC9zdmc+>>+--+darkseagreen :: Color+darkseagreen = rgba 143 188 143 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkslateblue' 'Color'.+--+-- >>> renderColor darkslateblue+-- "rgba(72,61,139,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3NsYXRlYmx1ZSIvPjwvc3ZnPg==>>+--+darkslateblue :: Color+darkslateblue = rgba 72 61 139 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkslategray' 'Color'.+--+-- >>> renderColor darkslategray+-- "rgba(47,79,79,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3NsYXRlZ3JheSIvPjwvc3ZnPg==>>+--+darkslategray :: Color+darkslategray = rgba 47 79 79 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkslategrey' 'Color'.+--+-- >>> renderColor darkslategrey+-- "rgba(47,79,79,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3NsYXRlZ3JleSIvPjwvc3ZnPg==>>+--+darkslategrey :: Color+darkslategrey = rgba 47 79 79 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkturquoise' 'Color'.+--+-- >>> renderColor darkturquoise+-- "rgba(0,206,209,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3R1cnF1b2lzZSIvPjwvc3ZnPg==>>+--+darkturquoise :: Color+darkturquoise = rgba 0 206 209 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'darkviolet' 'Color'.+--+-- >>> renderColor darkviolet+-- "rgba(148,0,211,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGFya3Zpb2xldCIvPjwvc3ZnPg==>>+--+darkviolet :: Color+darkviolet = rgba 148 0 211 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'deeppink' 'Color'.+--+-- >>> renderColor deeppink+-- "rgba(255,20,147,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGVlcHBpbmsiLz48L3N2Zz4=>>+--+deeppink :: Color+deeppink = rgba 255 20 147 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'deepskyblue' 'Color'.+--+-- >>> renderColor deepskyblue+-- "rgba(0,191,255,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGVlcHNreWJsdWUiLz48L3N2Zz4=>>+--+deepskyblue :: Color+deepskyblue = rgba 0 191 255 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'dimgray' 'Color'.+--+-- >>> renderColor dimgray+-- "rgba(105,105,105,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGltZ3JheSIvPjwvc3ZnPg==>>+--+dimgray :: Color+dimgray = rgba 105 105 105 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'dimgrey' 'Color'.+--+-- >>> renderColor dimgrey+-- "rgba(105,105,105,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZGltZ3JleSIvPjwvc3ZnPg==>>+--+dimgrey :: Color+dimgrey = rgba 105 105 105 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'dodgerblue' 'Color'.+--+-- >>> renderColor dodgerblue+-- "rgba(30,144,255,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZG9kZ2VyYmx1ZSIvPjwvc3ZnPg==>>+--+dodgerblue :: Color+dodgerblue = rgba 30 144 255 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'firebrick' 'Color'.+--+-- >>> renderColor firebrick+-- "rgba(178,34,34,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZmlyZWJyaWNrIi8+PC9zdmc+>>+--+firebrick :: Color+firebrick = rgba 178 34 34 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'floralwhite' 'Color'.+--+-- >>> renderColor floralwhite+-- "rgba(255,250,240,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZmxvcmFsd2hpdGUiLz48L3N2Zz4=>>+--+floralwhite :: Color+floralwhite = rgba 255 250 240 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'forestgreen' 'Color'.+--+-- >>> renderColor forestgreen+-- "rgba(34,139,34,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZm9yZXN0Z3JlZW4iLz48L3N2Zz4=>>+--+forestgreen :: Color+forestgreen = rgba 34 139 34 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'fuchsia' 'Color'.+--+-- >>> renderColor fuchsia+-- "rgba(255,0,255,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZnVjaHNpYSIvPjwvc3ZnPg==>>+--+fuchsia :: Color+fuchsia = rgba 255 0 255 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'gainsboro' 'Color'.+--+-- >>> renderColor gainsboro+-- "rgba(220,220,220,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ2FpbnNib3JvIi8+PC9zdmc+>>+--+gainsboro :: Color+gainsboro = rgba 220 220 220 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'ghostwhite' 'Color'.+--+-- >>> renderColor ghostwhite+-- "rgba(248,248,255,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ2hvc3R3aGl0ZSIvPjwvc3ZnPg==>>+--+ghostwhite :: Color+ghostwhite = rgba 248 248 255 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'gold' 'Color'.+--+-- >>> renderColor gold+-- "rgba(255,215,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ29sZCIvPjwvc3ZnPg==>>+--+gold :: Color+gold = rgba 255 215 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'goldenrod' 'Color'.+--+-- >>> renderColor goldenrod+-- "rgba(218,165,32,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ29sZGVucm9kIi8+PC9zdmc+>>+--+goldenrod :: Color+goldenrod = rgba 218 165 32 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'gray' 'Color'.+--+-- >>> renderColor gray+-- "rgba(128,128,128,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ3JheSIvPjwvc3ZnPg==>>+--+gray :: Color+gray = rgba 128 128 128 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'green' 'Color'.+--+-- >>> renderColor green+-- "rgba(0,128,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ3JlZW4iLz48L3N2Zz4=>>+--+green :: Color+green = rgba 0 128 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'greenyellow' 'Color'.+--+-- >>> renderColor greenyellow+-- "rgba(173,255,47,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ3JlZW55ZWxsb3ciLz48L3N2Zz4=>>+--+greenyellow :: Color+greenyellow = rgba 173 255 47 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'grey' 'Color'.+--+-- >>> renderColor grey+-- "rgba(128,128,128,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iZ3JleSIvPjwvc3ZnPg==>>+--+grey :: Color+grey = rgba 128 128 128 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'honeydew' 'Color'.+--+-- >>> renderColor honeydew+-- "rgba(240,255,240,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iaG9uZXlkZXciLz48L3N2Zz4=>>+--+honeydew :: Color+honeydew = rgba 240 255 240 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'hotpink' 'Color'.+--+-- >>> renderColor hotpink+-- "rgba(255,105,180,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iaG90cGluayIvPjwvc3ZnPg==>>+--+hotpink :: Color+hotpink = rgba 255 105 180 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'indianred' 'Color'.+--+-- >>> renderColor indianred+-- "rgba(205,92,92,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iaW5kaWFucmVkIi8+PC9zdmc+>>+--+indianred :: Color+indianred = rgba 205 92 92 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'indigo' 'Color'.+--+-- >>> renderColor indigo+-- "rgba(75,0,130,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iaW5kaWdvIi8+PC9zdmc+>>+--+indigo :: Color+indigo = rgba 75 0 130 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'ivory' 'Color'.+--+-- >>> renderColor ivory+-- "rgba(255,255,240,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iaXZvcnkiLz48L3N2Zz4=>>+--+ivory :: Color+ivory = rgba 255 255 240 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'khaki' 'Color'.+--+-- >>> renderColor khaki+-- "rgba(240,230,140,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ia2hha2kiLz48L3N2Zz4=>>+--+khaki :: Color+khaki = rgba 240 230 140 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lavender' 'Color'.+--+-- >>> renderColor lavender+-- "rgba(230,230,250,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGF2ZW5kZXIiLz48L3N2Zz4=>>+--+lavender :: Color+lavender = rgba 230 230 250 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lavenderblush' 'Color'.+--+-- >>> renderColor lavenderblush+-- "rgba(255,240,245,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGF2ZW5kZXJibHVzaCIvPjwvc3ZnPg==>>+--+lavenderblush :: Color+lavenderblush = rgba 255 240 245 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lawngreen' 'Color'.+--+-- >>> renderColor lawngreen+-- "rgba(124,252,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGF3bmdyZWVuIi8+PC9zdmc+>>+--+lawngreen :: Color+lawngreen = rgba 124 252 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lemonchiffon' 'Color'.+--+-- >>> renderColor lemonchiffon+-- "rgba(255,250,205,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGVtb25jaGlmZm9uIi8+PC9zdmc+>>+--+lemonchiffon :: Color+lemonchiffon = rgba 255 250 205 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightblue' 'Color'.+--+-- >>> renderColor lightblue+-- "rgba(173,216,230,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRibHVlIi8+PC9zdmc+>>+--+lightblue :: Color+lightblue = rgba 173 216 230 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightcoral' 'Color'.+--+-- >>> renderColor lightcoral+-- "rgba(240,128,128,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRjb3JhbCIvPjwvc3ZnPg==>>+--+lightcoral :: Color+lightcoral = rgba 240 128 128 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightcyan' 'Color'.+--+-- >>> renderColor lightcyan+-- "rgba(224,255,255,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRjeWFuIi8+PC9zdmc+>>+--+lightcyan :: Color+lightcyan = rgba 224 255 255 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightgoldenrodyellow' 'Color'.+--+-- >>> renderColor lightgoldenrodyellow+-- "rgba(250,250,210,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRnb2xkZW5yb2R5ZWxsb3ciLz48L3N2Zz4=>>+--+lightgoldenrodyellow :: Color+lightgoldenrodyellow = rgba 250 250 210 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightgray' 'Color'.+--+-- >>> renderColor lightgray+-- "rgba(211,211,211,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRncmF5Ii8+PC9zdmc+>>+--+lightgray :: Color+lightgray = rgba 211 211 211 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightgreen' 'Color'.+--+-- >>> renderColor lightgreen+-- "rgba(144,238,144,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRncmVlbiIvPjwvc3ZnPg==>>+--+lightgreen :: Color+lightgreen = rgba 144 238 144 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightgrey' 'Color'.+--+-- >>> renderColor lightgrey+-- "rgba(211,211,211,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRncmV5Ii8+PC9zdmc+>>+--+lightgrey :: Color+lightgrey = rgba 211 211 211 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightpink' 'Color'.+--+-- >>> renderColor lightpink+-- "rgba(255,182,193,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRwaW5rIi8+PC9zdmc+>>+--+lightpink :: Color+lightpink = rgba 255 182 193 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightsalmon' 'Color'.+--+-- >>> renderColor lightsalmon+-- "rgba(255,160,122,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRzYWxtb24iLz48L3N2Zz4=>>+--+lightsalmon :: Color+lightsalmon = rgba 255 160 122 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightseagreen' 'Color'.+--+-- >>> renderColor lightseagreen+-- "rgba(32,178,170,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRzZWFncmVlbiIvPjwvc3ZnPg==>>+--+lightseagreen :: Color+lightseagreen = rgba 32 178 170 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightskyblue' 'Color'.+--+-- >>> renderColor lightskyblue+-- "rgba(135,206,250,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRza3libHVlIi8+PC9zdmc+>>+--+lightskyblue :: Color+lightskyblue = rgba 135 206 250 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightslategray' 'Color'.+--+-- >>> renderColor lightslategray+-- "rgba(119,136,153,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRzbGF0ZWdyYXkiLz48L3N2Zz4=>>+--+lightslategray :: Color+lightslategray = rgba 119 136 153 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightslategrey' 'Color'.+--+-- >>> renderColor lightslategrey+-- "rgba(119,136,153,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRzbGF0ZWdyZXkiLz48L3N2Zz4=>>+--+lightslategrey :: Color+lightslategrey = rgba 119 136 153 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightsteelblue' 'Color'.+--+-- >>> renderColor lightsteelblue+-- "rgba(176,196,222,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHRzdGVlbGJsdWUiLz48L3N2Zz4=>>+--+lightsteelblue :: Color+lightsteelblue = rgba 176 196 222 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lightyellow' 'Color'.+--+-- >>> renderColor lightyellow+-- "rgba(255,255,224,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGlnaHR5ZWxsb3ciLz48L3N2Zz4=>>+--+lightyellow :: Color+lightyellow = rgba 255 255 224 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'lime' 'Color'.+--+-- >>> renderColor lime+-- "rgba(0,255,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGltZSIvPjwvc3ZnPg==>>+--+lime :: Color+lime = rgba 0 255 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'limegreen' 'Color'.+--+-- >>> renderColor limegreen+-- "rgba(50,205,50,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGltZWdyZWVuIi8+PC9zdmc+>>+--+limegreen :: Color+limegreen = rgba 50 205 50 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'linen' 'Color'.+--+-- >>> renderColor linen+-- "rgba(250,240,230,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibGluZW4iLz48L3N2Zz4=>>+--+linen :: Color+linen = rgba 250 240 230 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'magenta' 'Color'.+--+-- >>> renderColor magenta+-- "rgba(255,0,255,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWFnZW50YSIvPjwvc3ZnPg==>>+--+magenta :: Color+magenta = rgba 255 0 255 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'maroon' 'Color'.+--+-- >>> renderColor maroon+-- "rgba(128,0,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWFyb29uIi8+PC9zdmc+>>+--+maroon :: Color+maroon = rgba 128 0 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'mediumaquamarine' 'Color'.+--+-- >>> renderColor mediumaquamarine+-- "rgba(102,205,170,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtYXF1YW1hcmluZSIvPjwvc3ZnPg==>>+--+mediumaquamarine :: Color+mediumaquamarine = rgba 102 205 170 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'mediumblue' 'Color'.+--+-- >>> renderColor mediumblue+-- "rgba(0,0,205,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtYmx1ZSIvPjwvc3ZnPg==>>+--+mediumblue :: Color+mediumblue = rgba 0 0 205 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'mediumorchid' 'Color'.+--+-- >>> renderColor mediumorchid+-- "rgba(186,85,211,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtb3JjaGlkIi8+PC9zdmc+>>+--+mediumorchid :: Color+mediumorchid = rgba 186 85 211 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'mediumpurple' 'Color'.+--+-- >>> renderColor mediumpurple+-- "rgba(147,112,219,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtcHVycGxlIi8+PC9zdmc+>>+--+mediumpurple :: Color+mediumpurple = rgba 147 112 219 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'mediumseagreen' 'Color'.+--+-- >>> renderColor mediumseagreen+-- "rgba(60,179,113,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtc2VhZ3JlZW4iLz48L3N2Zz4=>>+--+mediumseagreen :: Color+mediumseagreen = rgba 60 179 113 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'mediumslateblue' 'Color'.+--+-- >>> renderColor mediumslateblue+-- "rgba(123,104,238,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtc2xhdGVibHVlIi8+PC9zdmc+>>+--+mediumslateblue :: Color+mediumslateblue = rgba 123 104 238 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'mediumspringgreen' 'Color'.+--+-- >>> renderColor mediumspringgreen+-- "rgba(0,250,154,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtc3ByaW5nZ3JlZW4iLz48L3N2Zz4=>>+--+mediumspringgreen :: Color+mediumspringgreen = rgba 0 250 154 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'mediumturquoise' 'Color'.+--+-- >>> renderColor mediumturquoise+-- "rgba(72,209,204,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtdHVycXVvaXNlIi8+PC9zdmc+>>+--+mediumturquoise :: Color+mediumturquoise = rgba 72 209 204 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'mediumvioletred' 'Color'.+--+-- >>> renderColor mediumvioletred+-- "rgba(199,21,133,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWVkaXVtdmlvbGV0cmVkIi8+PC9zdmc+>>+--+mediumvioletred :: Color+mediumvioletred = rgba 199 21 133 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'midnightblue' 'Color'.+--+-- >>> renderColor midnightblue+-- "rgba(25,25,112,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWlkbmlnaHRibHVlIi8+PC9zdmc+>>+--+midnightblue :: Color+midnightblue = rgba 25 25 112 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'mintcream' 'Color'.+--+-- >>> renderColor mintcream+-- "rgba(245,255,250,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWludGNyZWFtIi8+PC9zdmc+>>+--+mintcream :: Color+mintcream = rgba 245 255 250 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'mistyrose' 'Color'.+--+-- >>> renderColor mistyrose+-- "rgba(255,228,225,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibWlzdHlyb3NlIi8+PC9zdmc+>>+--+mistyrose :: Color+mistyrose = rgba 255 228 225 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'moccasin' 'Color'.+--+-- >>> renderColor moccasin+-- "rgba(255,228,181,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibW9jY2FzaW4iLz48L3N2Zz4=>>+--+moccasin :: Color+moccasin = rgba 255 228 181 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'navajowhite' 'Color'.+--+-- >>> renderColor navajowhite+-- "rgba(255,222,173,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibmF2YWpvd2hpdGUiLz48L3N2Zz4=>>+--+navajowhite :: Color+navajowhite = rgba 255 222 173 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'navy' 'Color'.+--+-- >>> renderColor navy+-- "rgba(0,0,128,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ibmF2eSIvPjwvc3ZnPg==>>+--+navy :: Color+navy = rgba 0 0 128 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'oldlace' 'Color'.+--+-- >>> renderColor oldlace+-- "rgba(253,245,230,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ib2xkbGFjZSIvPjwvc3ZnPg==>>+--+oldlace :: Color+oldlace = rgba 253 245 230 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'olive' 'Color'.+--+-- >>> renderColor olive+-- "rgba(128,128,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ib2xpdmUiLz48L3N2Zz4=>>+--+olive :: Color+olive = rgba 128 128 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'olivedrab' 'Color'.+--+-- >>> renderColor olivedrab+-- "rgba(107,142,35,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ib2xpdmVkcmFiIi8+PC9zdmc+>>+--+olivedrab :: Color+olivedrab = rgba 107 142 35 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'orange' 'Color'.+--+-- >>> renderColor orange+-- "rgba(255,165,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ib3JhbmdlIi8+PC9zdmc+>>+--+orange :: Color+orange = rgba 255 165 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'orangered' 'Color'.+--+-- >>> renderColor orangered+-- "rgba(255,69,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ib3JhbmdlcmVkIi8+PC9zdmc+>>+--+orangered :: Color+orangered = rgba 255 69 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'orchid' 'Color'.+--+-- >>> renderColor orchid+-- "rgba(218,112,214,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ib3JjaGlkIi8+PC9zdmc+>>+--+orchid :: Color+orchid = rgba 218 112 214 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'palegoldenrod' 'Color'.+--+-- >>> renderColor palegoldenrod+-- "rgba(238,232,170,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGFsZWdvbGRlbnJvZCIvPjwvc3ZnPg==>>+--+palegoldenrod :: Color+palegoldenrod = rgba 238 232 170 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'palegreen' 'Color'.+--+-- >>> renderColor palegreen+-- "rgba(152,251,152,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGFsZWdyZWVuIi8+PC9zdmc+>>+--+palegreen :: Color+palegreen = rgba 152 251 152 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'paleturquoise' 'Color'.+--+-- >>> renderColor paleturquoise+-- "rgba(175,238,238,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGFsZXR1cnF1b2lzZSIvPjwvc3ZnPg==>>+--+paleturquoise :: Color+paleturquoise = rgba 175 238 238 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'palevioletred' 'Color'.+--+-- >>> renderColor palevioletred+-- "rgba(219,112,147,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGFsZXZpb2xldHJlZCIvPjwvc3ZnPg==>>+--+palevioletred :: Color+palevioletred = rgba 219 112 147 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'papayawhip' 'Color'.+--+-- >>> renderColor papayawhip+-- "rgba(255,239,213,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGFwYXlhd2hpcCIvPjwvc3ZnPg==>>+--+papayawhip :: Color+papayawhip = rgba 255 239 213 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'peachpuff' 'Color'.+--+-- >>> renderColor peachpuff+-- "rgba(255,218,185,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGVhY2hwdWZmIi8+PC9zdmc+>>+--+peachpuff :: Color+peachpuff = rgba 255 218 185 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'peru' 'Color'.+--+-- >>> renderColor peru+-- "rgba(205,133,63,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGVydSIvPjwvc3ZnPg==>>+--+peru :: Color+peru = rgba 205 133 63 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'pink' 'Color'.+--+-- >>> renderColor pink+-- "rgba(255,192,203,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGluayIvPjwvc3ZnPg==>>+--+pink :: Color+pink = rgba 255 192 203 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'plum' 'Color'.+--+-- >>> renderColor plum+-- "rgba(221,160,221,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icGx1bSIvPjwvc3ZnPg==>>+--+plum :: Color+plum = rgba 221 160 221 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'powderblue' 'Color'.+--+-- >>> renderColor powderblue+-- "rgba(176,224,230,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icG93ZGVyYmx1ZSIvPjwvc3ZnPg==>>+--+powderblue :: Color+powderblue = rgba 176 224 230 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'purple' 'Color'.+--+-- >>> renderColor purple+-- "rgba(128,0,128,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icHVycGxlIi8+PC9zdmc+>>+--+purple :: Color+purple = rgba 128 0 128 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'red' 'Color'.+--+-- >>> renderColor red+-- "rgba (255,0,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icmVkIi8+PC9zdmc+>>+--+red :: Color+red = rgba 255 0 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'rosybrown' 'Color'.+--+-- >>> renderColor rosybrown+-- "rgba(188,143,143,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icm9zeWJyb3duIi8+PC9zdmc+>>+--+rosybrown :: Color+rosybrown = rgba 188 143 143 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'royalblue' 'Color'.+--+-- >>> renderColor royalblue+-- "rgba(65,105,225,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0icm95YWxibHVlIi8+PC9zdmc+>>+--+royalblue :: Color+royalblue = rgba 65 105 225 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'saddlebrown' 'Color'.+--+-- >>> renderColor saddlebrown+-- "rgba(139,69,19,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2FkZGxlYnJvd24iLz48L3N2Zz4=>>+--+saddlebrown :: Color+saddlebrown = rgba 139 69 19 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'salmon' 'Color'.+--+-- >>> renderColor salmon+-- "rgba(250,128,114,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2FsbW9uIi8+PC9zdmc+>>+--+salmon :: Color+salmon = rgba 250 128 114 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'sandybrown' 'Color'.+--+-- >>> renderColor sandybrown+-- "rgba(244,164,96,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2FuZHlicm93biIvPjwvc3ZnPg==>>+--+sandybrown :: Color+sandybrown = rgba 244 164 96 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'seagreen' 'Color'.+--+-- >>> renderColor seagreen+-- "rgba(46,139,87,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2VhZ3JlZW4iLz48L3N2Zz4=>>+--+seagreen :: Color+seagreen = rgba 46 139 87 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'seashell' 'Color'.+--+-- >>> renderColor seashell+-- "rgba(255,245,238,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2Vhc2hlbGwiLz48L3N2Zz4=>>+--+seashell :: Color+seashell = rgba 255 245 238 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'sienna' 'Color'.+--+-- >>> renderColor sienna+-- "rgba(160,82,45,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2llbm5hIi8+PC9zdmc+>>+--+sienna :: Color+sienna = rgba 160 82 45 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'silver' 'Color'.+--+-- >>> renderColor silver+-- "rgba(192,192,192,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2lsdmVyIi8+PC9zdmc+>>+--+silver :: Color+silver = rgba 192 192 192 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'skyblue' 'Color'.+--+-- >>> renderColor skyblue+-- "rgba(135,206,235,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2t5Ymx1ZSIvPjwvc3ZnPg==>>+--+skyblue :: Color+skyblue = rgba 135 206 235 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'slateblue' 'Color'.+--+-- >>> renderColor slateblue+-- "rgba(106,90,205,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2xhdGVibHVlIi8+PC9zdmc+>>+--+slateblue :: Color+slateblue = rgba 106 90 205 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'slategray' 'Color'.+--+-- >>> renderColor slategray+-- "rgba(112,128,144,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2xhdGVncmF5Ii8+PC9zdmc+>>+--+slategray :: Color+slategray = rgba 112 128 144 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'slategrey' 'Color'.+--+-- >>> renderColor slategrey+-- "rgba(112,128,144,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic2xhdGVncmV5Ii8+PC9zdmc+>>+--+slategrey :: Color+slategrey = rgba 112 128 144 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'snow' 'Color'.+--+-- >>> renderColor snow+-- "rgba(255,250,250,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic25vdyIvPjwvc3ZnPg==>>+--+snow :: Color+snow = rgba 255 250 250 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'springgreen' 'Color'.+--+-- >>> renderColor springgreen+-- "rgba(0,255,127,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic3ByaW5nZ3JlZW4iLz48L3N2Zz4=>>+--+springgreen :: Color+springgreen = rgba 0 255 127 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'steelblue' 'Color'.+--+-- >>> renderColor steelblue+-- "rgba(70,130,180,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ic3RlZWxibHVlIi8+PC9zdmc+>>+--+steelblue :: Color+steelblue = rgba 70 130 180 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'tan' 'Color'.+--+-- >>> renderColor tan+-- "rgba(210,180,140,1.<<data:image/svg+xml;base64,0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0idGFuIi8+PC9zdmc+>>+--+tan :: Color+tan = rgba 210 180 140 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'teal' 'Color'.+--+-- >>> renderColor teal+-- "rgba(0,128,128,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0idGVhbCIvPjwvc3ZnPg==>>+--+teal :: Color+teal = rgba 0 128 128 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'thistle' 'Color'.+--+-- >>> renderColor thistle+-- "rgba(216,191,216,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0idGhpc3RsZSIvPjwvc3ZnPg==>>+--+thistle :: Color+thistle = rgba 216 191 216 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'tomato' 'Color'.+--+-- >>> renderColor tomato+-- "rgba(255,99,71,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0idG9tYXRvIi8+PC9zdmc+>>+--+tomato :: Color+tomato = rgba 255 99 71 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'turquoise' 'Color'.+--+-- >>> renderColor turquoise+-- "rgba(64,224,208,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0idHVycXVvaXNlIi8+PC9zdmc+>>+--+turquoise :: Color+turquoise = rgba 64 224 208 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'violet' 'Color'.+--+-- >>> renderColor violet+-- "rgba(238,130,238,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0idmlvbGV0Ii8+PC9zdmc+>>+--+violet :: Color+violet = rgba 238 130 238 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'wheat' 'Color'.+--+-- >>> renderColor wheat+-- "rgba(245,222,179,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0id2hlYXQiLz48L3N2Zz4=>>+--+wheat :: Color+wheat = rgba 245 222 179 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'white' 'Color'.+--+-- >>> renderColor white+-- "rgba(255,255,255,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0id2hpdGUiLz48L3N2Zz4=>>+--+white :: Color+white = rgba 255 255 255 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'whitesmoke' 'Color'.+--+-- >>> renderColor whitesmoke+-- "rgba(245,245,245,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0id2hpdGVzbW9rZSIvPjwvc3ZnPg==>>+--+whitesmoke :: Color+whitesmoke = rgba 245 245 245 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'yellow' 'Color'.+--+-- >>> renderColor yellow+-- "rgba(255,255,0,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ieWVsbG93Ii8+PC9zdmc+>>+--+yellow :: Color+yellow = rgba 255 255 0 1+-----------------------------------------------------------------------------+-- | Smart constructor for the 'yellowgreen' 'Color'.+--+-- >>> renderColor yellowgreen+-- "rgba(154,205,50,1.0)"+--+-- <<data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0ieWVsbG93Z3JlZW4iLz48L3N2Zz4=>>+--+yellowgreen :: Color+yellowgreen = rgba 154 205 50 1+-----------------------------------------------------------------------------
+ src/Miso/CSS/Types.hs view
@@ -0,0 +1,75 @@+-----------------------------------------------------------------------------+-- |+-- Module : Miso.CSS.Types+-- Copyright : (C) 2016-2026 David M. Johnson (@dmjio)+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- Types for CSS, including inline styles and [StyleSheets](https://developer.mozilla.org/en-US/docs/Web/API/StyleSheet).+--+----------------------------------------------------------------------------+module Miso.CSS.Types+ ( -- *** Types+ Style+ , Styles (..)+ , StyleSheet (..)+ ) where+-----------------------------------------------------------------------------+import Miso.String (MisoString)+-----------------------------------------------------------------------------+-- | Type for a CSS StyleSheet. Internally it maps From CSS selectors to t'Styles'.+--+-- @+-- testSheet :: StyleSheet+-- testSheet =+-- sheet_+-- [ selector_ ".name"+-- [ backgroundColor red+-- , alignContent "top"+-- ]+-- , selector_ "#container"+-- [ backgroundColor blue+-- , alignContent "center"+-- ]+-- , keyframes_ "slide-in"+-- [ "from" =:+-- [ transform "translateX(0%)"+-- ]+-- , "to" =:+-- [ transform "translateX(100%)"+-- , backgroundColor red+-- , backgroundSize "10px"+-- , backgroundRepeat "true"+-- ]+-- , pct 10 =:+-- [ "foo" =: "bar"+-- ]+-- ]+-- , media_ "screen and (min-width: 480px)"+-- [ "header" =:+-- [ height "auto"+-- ]+-- , "ul" =:+-- [ display "block"+-- ]+-- ]+-- ]+-- @+--+newtype StyleSheet = StyleSheet { getStyleSheet :: [Styles] }+ deriving (Eq, Show)+-----------------------------------------------------------------------------+-- | Type for a CSS 'Style'+--+type Style = (MisoString, MisoString)+-----------------------------------------------------------------------------+-- | Type for a @Map@ of CSS 'Style'. Used with @StyleSheet@.+-- It maps CSS properties to their values.+data Styles+ = Styles (MisoString, [Style])+ | KeyFrame MisoString [(MisoString, [Style])]+ | Media MisoString [(MisoString, [Style])]+ deriving (Eq, Show)+-----------------------------------------------------------------------------
+ src/Miso/Canvas.hs view
@@ -0,0 +1,634 @@+-----------------------------------------------------------------------------+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE CPP #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Canvas+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+----------------------------------------------------------------------------+module Miso.Canvas+ ( -- * Types+ Canvas+ , CanvasContext2D+ , Pattern (..)+ , Gradient (..)+ , ImageData (..)+ , LineCapType (..)+ , PatternType (..)+ , LineJoinType (..)+ , DirectionType (..)+ , TextAlignType (..)+ , TextBaselineType (..)+ , CompositeOperation (..)+ , StyleArg (..)+ , Coord+ -- * Property+ , canvas+ , canvas_+ -- * API+ , set+ , globalCompositeOperation+ , clearRect+ , fillRect+ , strokeRect+ , beginPath+ , closePath+ , moveTo+ , lineTo+ , fill+ , rect+ , stroke+ , bezierCurveTo+ , arc+ , arcTo+ , quadraticCurveTo+ , direction+ , fillText+ , font+ , strokeText+ , textAlign+ , textBaseline+ , addColorStop+ , createLinearGradient+ , createPattern+ , createRadialGradient+ , fillStyle+ , lineCap+ , lineJoin+ , lineWidth+ , miterLimit+ , shadowBlur+ , shadowColor+ , shadowOffsetX+ , shadowOffsetY+ , strokeStyle+ , scale+ , rotate+ , translate+ , transform+ , setTransform+ , drawImage+ , drawImage'+ , createImageData+ , getImageData+ , setImageData+ , height+ , width+ , putImageData+ , globalAlpha+ , clip+ , save+ , restore+ -- * Smart constructors+ , gradient+ , pattern_+ , color+ ) where+-----------------------------------------------------------------------------+import Control.Monad.IO.Class (liftIO)+import Control.Monad.Reader (ReaderT, runReaderT, ask)+-----------------------------------------------------------------------------+import Miso.DSL hiding (call)+import qualified Miso.FFI as FFI+import Miso.FFI (Image)+import Miso.Types+import Miso.CSS (Color, renderColor)+-----------------------------------------------------------------------------+-- | Another variant of canvas, this is not specialized to 'ReaderT'. This is+-- useful when building applications with three.js, or other libraries where+-- explicit context is not necessary.+canvas_+ :: forall model action canvasState+ . (FromJSVal canvasState, ToJSVal canvasState)+ => [ Attribute action ]+ -> (DOMRef -> IO canvasState)+ -- ^ Init function, takes 'DOMRef' as arg, returns canvas init. state.+ -> (canvasState -> IO ())+ -- ^ Callback to render graphics using this canvas' context, takes init state as arg.+ -> View model action+canvas_ attributes initialize_ draw_ = node HTML "canvas" attrs []+ where+ attrs :: [ Attribute action ]+ attrs = initCallback : drawCallack : attributes++ initCallback :: Attribute action+ initCallback = On $ \_ (VTree vtree) _ _ -> do+ flip (FFI.set "onCreated") vtree =<< do+ FFI.syncCallback1 $ \domRef -> do+ initialState <- initialize_ domRef+ FFI.set "state" initialState (Object domRef)++ drawCallack :: Attribute action+ drawCallack = On $ \_ (VTree vtree) _ _ -> do+ flip (FFI.set "draw") vtree =<< do+ FFI.syncCallback1 $ \domRef -> do+ state <- fromJSValUnchecked =<< domRef ! ("state" :: MisoString)+ draw_ state+-----------------------------------------------------------------------------+-- | Element for drawing on a [\<canvas\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/canvas).+-- This function abstracts over the context and interpret callback,+-- including dimension ("2d" or "3d") canvas.+canvas+ :: forall model action canvasState+ . (FromJSVal canvasState, ToJSVal canvasState)+ => [ Attribute action ]+ -> (DOMRef -> Canvas canvasState)+ -- ^ Init function, takes 'DOMRef' as arg, returns canvas init. state.+ -> (canvasState -> Canvas ())+ -- ^ Callback to render graphics using this canvas' context, takes init state as arg.+ -> View model action+canvas attributes initialize draw = node HTML "canvas" attrs []+ where+ attrs :: [ Attribute action ]+ attrs = initCallback : drawCallack : attributes++ initCallback :: Attribute action+ initCallback = On $ \_ (VTree vtree) _ _ -> do+ flip (FFI.set "onCreated") vtree =<< do+ FFI.syncCallback1 $ \domRef -> do+ ctx <- domRef # ("getContext" :: MisoString) $ ["2d" :: MisoString]+ initialState <- runReaderT (initialize domRef) ctx+ FFI.set "state" initialState (Object domRef)++ drawCallack :: Attribute action+ drawCallack = On $ \_ (VTree vtree) _ _ -> do+ flip (FFI.set "draw") vtree =<< do+ FFI.syncCallback1 $ \domRef -> do+ jval <- domRef ! ("state" :: MisoString)+ initialState <- fromJSValUnchecked jval+ ctx <- domRef # ("getContext" :: MisoString) $ ["2d" :: MisoString]+ runReaderT (draw initialState) ctx+-----------------------------------------------------------------------------+-- | Various patterns used in the canvas API+data PatternType = Repeat | RepeatX | RepeatY | NoRepeat+-----------------------------------------------------------------------------+instance ToJSVal PatternType where+ toJSVal = toJSVal . renderPattern+-----------------------------------------------------------------------------+instance FromJSVal PatternType where+ fromJSVal pat =+ fromJSValUnchecked @MisoString pat >>= \case+ "repeat" -> pure (Just Repeat)+ "repeat-x" -> pure (Just RepeatX)+ "repeat-y" -> pure (Just RepeatY)+ "no-repeat" -> pure (Just NoRepeat)+ _ -> pure Nothing+-----------------------------------------------------------------------------+-- | Color, Gradient or Pattern styling+data StyleArg+ = ColorArg Color+ | GradientArg Gradient+ | PatternArg Pattern+-----------------------------------------------------------------------------+-- | Smart constructor for 'Color' when using 'StyleArg'+color :: Color -> StyleArg+color = ColorArg+-----------------------------------------------------------------------------+-- | Smart constructor for t'Gradient' when using t'StyleArg'+gradient :: Gradient -> StyleArg+gradient = GradientArg+-----------------------------------------------------------------------------+-- | Smart constructor for t'Pattern' when using t'StyleArg'+pattern_ :: Pattern -> StyleArg+pattern_ = PatternArg+-----------------------------------------------------------------------------+-- | Renders a t'StyleArg' to a 'JSVal'+renderStyleArg :: StyleArg -> IO JSVal+renderStyleArg = \case+ ColorArg c -> toJSVal (renderColor c)+ GradientArg g -> toJSVal g+ PatternArg p -> toJSVal p+-----------------------------------------------------------------------------+instance ToArgs StyleArg where+ toArgs arg = (:[]) <$> toJSVal arg+-----------------------------------------------------------------------------+instance ToJSVal StyleArg where+ toJSVal = renderStyleArg+-----------------------------------------------------------------------------+-- | Pretty-prints a t'PatternType' as 'Miso.String.MisoString'+renderPattern :: PatternType -> MisoString+renderPattern = \case+ Repeat -> "repeat"+ RepeatX -> "repeat-x"+ RepeatY -> "repeat-y"+ NoRepeat -> "no-repeat"+-----------------------------------------------------------------------------+-- | [LineCap](https://www.w3schools.com/tags/canvas_linecap.asp)+data LineCapType+ = LineCapButt+ | LineCapRound+ | LineCapSquare+ deriving (Show, Eq)+-----------------------------------------------------------------------------+instance ToArgs LineCapType where+ toArgs arg = (:[]) <$> toJSVal arg+-----------------------------------------------------------------------------+instance ToJSVal LineCapType where+ toJSVal = toJSVal . renderLineCapType+-----------------------------------------------------------------------------+-- | Pretty-printing for 'LineCapType'+renderLineCapType :: LineCapType -> MisoString+renderLineCapType = \case+ LineCapButt -> "butt"+ LineCapRound -> "round"+ LineCapSquare -> "square"+-----------------------------------------------------------------------------+-- | [LineJoin](https://www.w3schools.com/tags/canvas_linejoin.asp)+data LineJoinType+ = LineJoinBevel+ | LineJoinRound+ | LineJoinMiter+ deriving (Show, Eq)+-----------------------------------------------------------------------------+instance ToArgs LineJoinType where+ toArgs arg = (:[]) <$> toJSVal arg+-----------------------------------------------------------------------------+instance ToJSVal LineJoinType where+ toJSVal = toJSVal . renderLineJoinType+-----------------------------------------------------------------------------+-- | Pretty-print a 'LineJoinType'+renderLineJoinType :: LineJoinType -> MisoString+renderLineJoinType = \case+ LineJoinBevel -> "bevel"+ LineJoinRound -> "round"+ LineJoinMiter -> "miter"+-----------------------------------------------------------------------------+-- | Left-to-right, right-to-left, or inherit direction type.+data DirectionType+ = LTR+ | RTL+ | Inherit+ deriving (Show, Eq)+-----------------------------------------------------------------------------+instance ToArgs DirectionType where+ toArgs arg = (:[]) <$> toJSVal arg+-----------------------------------------------------------------------------+instance ToJSVal DirectionType where+ toJSVal = toJSVal . renderDirectionType+-----------------------------------------------------------------------------+-- | Pretty-printing for 'DirectionType'+renderDirectionType :: DirectionType -> MisoString+renderDirectionType = \case+ LTR -> "ltr"+ RTL -> "rtl"+ Inherit -> "inherit"+-----------------------------------------------------------------------------+-- | Text alignment type+data TextAlignType+ = TextAlignCenter+ | TextAlignEnd+ | TextAlignLeft+ | TextAlignRight+ | TextAlignStart+ deriving (Show, Eq)+-----------------------------------------------------------------------------+instance ToArgs TextAlignType where+ toArgs arg = (:[]) <$> toJSVal arg+-----------------------------------------------------------------------------+instance ToJSVal TextAlignType where+ toJSVal = toJSVal . renderTextAlignType+-----------------------------------------------------------------------------+-- | Pretty-print 'TextAlignType'+renderTextAlignType :: TextAlignType -> MisoString+renderTextAlignType = \case+ TextAlignCenter -> "center"+ TextAlignEnd -> "end"+ TextAlignLeft -> "left"+ TextAlignRight -> "right"+ TextAlignStart -> "start"+-----------------------------------------------------------------------------+-- | TextBaselineType+data TextBaselineType+ = TextBaselineAlphabetic+ | TextBaselineTop+ | TextBaselineHanging+ | TextBaselineMiddle+ | TextBaselineIdeographic+ | TextBaselineBottom+ deriving (Show, Eq)+-----------------------------------------------------------------------------+instance ToArgs TextBaselineType where+ toArgs arg = (:[]) <$> toJSVal arg+-----------------------------------------------------------------------------+instance ToJSVal TextBaselineType where+ toJSVal = toJSVal . renderTextBaselineType+-----------------------------------------------------------------------------+-- | Pretty-printing for 'TextBaselineType'+renderTextBaselineType :: TextBaselineType -> MisoString+renderTextBaselineType = \case+ TextBaselineAlphabetic -> "alphabetic"+ TextBaselineTop -> "top"+ TextBaselineHanging -> "hanging"+ TextBaselineMiddle -> "middle"+ TextBaselineIdeographic -> "ideographic"+ TextBaselineBottom -> "bottom"+-----------------------------------------------------------------------------+-- | CompositeOperation+data CompositeOperation+ = SourceOver+ | SourceAtop+ | SourceIn+ | SourceOut+ | DestinationOver+ | DestinationAtop+ | DestinationIn+ | DestinationOut+ | Lighter+ | Copy+ | Xor+ deriving (Show, Eq)+-----------------------------------------------------------------------------+instance ToArgs CompositeOperation where+ toArgs arg = (:[]) <$> toJSVal arg+-----------------------------------------------------------------------------+instance ToJSVal CompositeOperation where+ toJSVal = toJSVal . renderCompositeOperation+-----------------------------------------------------------------------------+-- | Pretty-print a 'CompositeOperation'+renderCompositeOperation :: CompositeOperation -> MisoString+renderCompositeOperation = \case+ SourceOver -> "source-over"+ SourceAtop -> "source-atop"+ SourceIn -> "source-in"+ SourceOut -> "source-out"+ DestinationOver -> "destination-over"+ DestinationAtop -> "destination-atop"+ DestinationIn -> "destination-in"+ DestinationOut -> "destination-out"+ Lighter -> "lighter"+ Copy -> "copy"+ Xor -> "xor"+-----------------------------------------------------------------------------+-- | Type used to hold a canvas Pattern+newtype Pattern = Pattern JSVal deriving (ToJSVal)+-----------------------------------------------------------------------------+instance FromJSVal Pattern where+ fromJSVal = pure . pure . Pattern+-----------------------------------------------------------------------------+-- | Type used to hold a Gradient+newtype Gradient = Gradient JSVal deriving (ToJSVal, ToArgs)+-----------------------------------------------------------------------------+instance FromJSVal Gradient where+ fromJSVal = pure . pure . Gradient+-----------------------------------------------------------------------------+-- | Type used to hold t'ImageData'+newtype ImageData = ImageData JSVal deriving (ToJSVal, ToObject)+-----------------------------------------------------------------------------+instance ToArgs ImageData where+ toArgs args = (:[]) <$> toJSVal args+-----------------------------------------------------------------------------+instance FromJSVal ImageData where+ fromJSVal = pure . pure . ImageData+-----------------------------------------------------------------------------+-- | An (x,y) coordinate.+type Coord = (Double, Double)+-----------------------------------------------------------------------------+-- | The canvas t'CanvasContext2D'+type CanvasContext2D = JSVal+-----------------------------------------------------------------------------+call :: (FromJSVal a, ToArgs args) => MisoString -> args -> Canvas a+call name arg = do+ ctx <- ask+ liftIO $ fromJSValUnchecked =<< do+ ctx # name $ arg+-----------------------------------------------------------------------------+-- | Property setter specialized to t'Canvas'.+--+-- @+-- globalCompositeOperation :: CompositeOperation -> Canvas ()+-- globalCompositeOperation = set "globalCompositeOperation"+-- @+--+set :: ToArgs args => MisoString -> args -> Canvas ()+set name args = do+ ctx <- ask+ liftIO $ setField ctx name (toArgs args)+-----------------------------------------------------------------------------+-- | DSL for expressing operations on 'canvas_'+type Canvas a = ReaderT CanvasContext2D IO a+-----------------------------------------------------------------------------+-- | [ctx.globalCompositeOperation = "source-over"](https://www.w3schools.com/tags/canvas_globalcompositeoperation.asp)+globalCompositeOperation :: CompositeOperation -> Canvas ()+globalCompositeOperation = set "globalCompositeOperation"+-----------------------------------------------------------------------------+-- | [ctx.clearRect(x,y,width,height)](https://www.w3schools.com/tags/canvas_clearrect.asp)+clearRect :: (Double, Double, Double, Double) -> Canvas ()+clearRect = call "clearRect"+-----------------------------------------------------------------------------+-- | [ctx.fillRect(x,y,width,height)](https://www.w3schools.com/tags/canvas_fillrect.asp)+fillRect :: (Double, Double, Double, Double) -> Canvas ()+fillRect = call "fillRect"+-----------------------------------------------------------------------------+-- | [ctx.strokeRect(x,y,width,height)](https://www.w3schools.com/tags/canvas_strokerect.asp)+strokeRect :: (Double, Double, Double, Double) -> Canvas ()+strokeRect = call "strokeRect"+-----------------------------------------------------------------------------+-- | [ctx.beginPath()](https://www.w3schools.com/tags/canvas_beginpath.asp)+beginPath :: () -> Canvas ()+beginPath = call "beginPath"+-----------------------------------------------------------------------------+-- | [ctx.closePath()](https://www.w3schools.com/tags/canvas_closepath.asp)+closePath :: () -> Canvas ()+closePath = call "closePath"+-----------------------------------------------------------------------------+-- | [ctx.moveTo(x,y)](https://www.w3schools.com/tags/canvas_moveto.asp)+moveTo :: Coord -> Canvas ()+moveTo = call "moveTo"+-----------------------------------------------------------------------------+-- | [ctx.lineTo(x,y)](https://www.w3schools.com/tags/canvas_lineto.asp)+lineTo :: Coord -> Canvas ()+lineTo = call "lineTo"+-----------------------------------------------------------------------------+-- | [ctx.fill()](https://www.w3schools.com/tags/canvas_fill.asp)+fill :: () -> Canvas ()+fill = call "fill"+-----------------------------------------------------------------------------+-- | [ctx.rect(x,y,width,height)](https://www.w3schools.com/tags/canvas_rect.asp)+rect :: (Double, Double, Double, Double) -> Canvas ()+rect = call "rect"+-----------------------------------------------------------------------------+-- | [ctx.stroke()](https://www.w3schools.com/tags/canvas_stroke.asp)+stroke :: () -> Canvas ()+stroke = call "stroke"+-----------------------------------------------------------------------------+-- | [ctx.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y)](https://www.w3schools.com/tags/canvas_beziercurveto.asp)+bezierCurveTo :: (Double, Double, Double, Double, Double, Double) -> Canvas ()+bezierCurveTo = call "bezierCurveTo"+-----------------------------------------------------------------------------+-- | [context.arc(x, y, r, sAngle, eAngle, counterclockwise)](https://www.w3schools.com/tags/canvas_arc.asp)+arc :: (Double, Double, Double, Double, Double) -> Canvas ()+arc = call "arc"+-----------------------------------------------------------------------------+-- | [context.arcTo(x1, y1, x2, y2, r)](https://www.w3schools.com/tags/canvas_arcto.asp)+arcTo :: (Double, Double, Double, Double, Double) -> Canvas ()+arcTo = call "arcTo"+-----------------------------------------------------------------------------+-- | [context.quadraticCurveTo(cpx,cpy,x,y)](https://www.w3schools.com/tags/canvas_quadraticcurveto.asp)+quadraticCurveTo :: (Double, Double, Double, Double) -> Canvas ()+quadraticCurveTo = call "quadraticCurveTo"+-----------------------------------------------------------------------------+-- | [context.direction = "ltr"](https://www.w3schools.com/tags/canvas_direction.asp)+direction :: DirectionType -> Canvas ()+direction = set "direction"+-----------------------------------------------------------------------------+-- | [context.fillText(text,x,y)](https://www.w3schools.com/tags/canvas_filltext.asp)+fillText :: (MisoString, Double, Double) -> Canvas ()+fillText = call "fillText"+-----------------------------------------------------------------------------+-- | [context.font = "italic small-caps bold 12px arial"](https://www.w3schools.com/tags/canvas_font.asp)+font :: MisoString -> Canvas ()+font = set "font"+-----------------------------------------------------------------------------+-- | [ctx.strokeText()](https://www.w3schools.com/tags/canvas_stroketext.asp)+strokeText :: (MisoString, Double, Double) -> Canvas ()+strokeText = call "strokeText"+-----------------------------------------------------------------------------+-- | [ctx.textAlign = "start"](https://www.w3schools.com/tags/canvas_textalign.asp)+textAlign :: TextAlignType -> Canvas ()+textAlign = set "textAlign"+-----------------------------------------------------------------------------+-- | [ctx.textBaseline = "top"](https://www.w3schools.com/tags/canvas_textBaseLine.asp)+textBaseline :: TextBaselineType -> Canvas ()+textBaseline = set "textBaseline"+-----------------------------------------------------------------------------+-- | [gradient.addColorStop(stop,color)](https://www.w3schools.com/tags/canvas_addcolorstop.asp)+addColorStop :: (Double, Color) -> Gradient -> Canvas ()+addColorStop args (Gradient g) = do+ _ <- liftIO $ g # ("addColorStop" :: MisoString) $ args+ pure ()+-----------------------------------------------------------------------------+-- | [ctx.createLinearGradient(x0,y0,x1,y1)](https://www.w3schools.com/tags/canvas_createlineargradient.asp)+createLinearGradient :: (Double, Double, Double, Double) -> Canvas Gradient+createLinearGradient = call "createLinearGradient"+-----------------------------------------------------------------------------+-- | [ctx.createPattern(image, "repeat")](https://www.w3schools.com/tags/canvas_createpattern.asp)+createPattern :: (Image, PatternType) -> Canvas Pattern+createPattern = call "createPattern"+-----------------------------------------------------------------------------+-- | [ctx.createRadialGradient(x0,y0,r0,x1,y1,r1)](https://www.w3schools.com/tags/canvas_createradialgradient.asp)+createRadialGradient :: (Double,Double,Double,Double,Double,Double) -> Canvas Gradient+createRadialGradient = call "createRadialGradient"+-----------------------------------------------------------------------------+-- | [ctx.fillStyle = "red"](https://www.w3schools.com/tags/canvas_fillstyle.asp)+fillStyle :: StyleArg -> Canvas ()+fillStyle = set "fillStyle"+-----------------------------------------------------------------------------+-- | [ctx.lineCap = "butt"](https://www.w3schools.com/tags/canvas_lineCap.asp)+lineCap :: LineCapType -> Canvas ()+lineCap = set "lineCap"+-----------------------------------------------------------------------------+-- | [ctx.lineJoin = "bevel"](https://www.w3schools.com/tags/canvas_lineJoin.asp)+lineJoin :: LineJoinType -> Canvas ()+lineJoin = set "lineJoin"+-----------------------------------------------------------------------------+-- | [ctx.lineWidth = 10](https://www.w3schools.com/tags/canvas_lineWidth.asp)+lineWidth :: Double -> Canvas ()+lineWidth = set "lineWidth"+-----------------------------------------------------------------------------+-- | [ctx.miterLimit = 10](https://www.w3schools.com/tags/canvas_miterLimit.asp)+miterLimit :: Double -> Canvas ()+miterLimit = set "miterLimit"+-----------------------------------------------------------------------------+-- | [ctx.shadowBlur = 10](https://www.w3schools.com/tags/canvas_shadowBlur.asp)+shadowBlur :: Double -> Canvas ()+shadowBlur = set "shadowBlur"+-----------------------------------------------------------------------------+-- | [ctx.shadowColor = "red"](https://www.w3schools.com/tags/canvas_shadowColor.asp)+shadowColor :: Color -> Canvas ()+shadowColor = set "shadowColor"+-----------------------------------------------------------------------------+-- | [ctx.shadowOffsetX = 20](https://www.w3schools.com/tags/canvas_shadowOffsetX.asp)+shadowOffsetX :: Double -> Canvas ()+shadowOffsetX = set "shadowOffsetX"+-----------------------------------------------------------------------------+-- | [ctx.shadowOffsetY = 20](https://www.w3schools.com/tags/canvas_shadowOffsetY.asp)+shadowOffsetY :: Double -> Canvas ()+shadowOffsetY = set "shadowOffsetY"+-----------------------------------------------------------------------------+-- | [ctx.strokeStyle = "red"](https://www.w3schools.com/tags/canvas_strokeStyle.asp)+strokeStyle :: StyleArg -> Canvas ()+strokeStyle = set "strokeStyle"+-----------------------------------------------------------------------------+-- | [ctx.scale(width,height)](https://www.w3schools.com/tags/canvas_scale.asp)+scale :: (Double, Double) -> Canvas ()+scale = call "scale"+-----------------------------------------------------------------------------+-- | [ctx.rotate(angle)](https://www.w3schools.com/tags/canvas_rotate.asp)+rotate :: Double -> Canvas ()+rotate = call "rotate"+-----------------------------------------------------------------------------+-- | [ctx.translate(angle)](https://www.w3schools.com/tags/canvas_translate.asp)+translate :: Coord -> Canvas ()+translate = call "translate"+-----------------------------------------------------------------------------+-- | [ctx.transform(a,b,c,d,e,f)](https://www.w3schools.com/tags/canvas_transform.asp)+transform :: (Double, Double, Double, Double, Double, Double) -> Canvas ()+transform = call "transform"+-----------------------------------------------------------------------------+-- | [ctx.setTransform(a,b,c,d,e,f)](https://www.w3schools.com/tags/canvas_setTransform.asp)+setTransform :: (Double, Double, Double, Double, Double, Double) -> Canvas ()+setTransform = call "setTransform"+----------------------------------------------------------------------------+-- | [ctx.drawImage(image,x,y)](https://www.w3schools.com/tags/canvas_drawImage.asp)+drawImage :: (Image, Double, Double) -> Canvas ()+drawImage = call "drawImage"+-----------------------------------------------------------------------------+-- | [ctx.drawImage(image,x,y)](https://www.w3schools.com/tags/canvas_drawImage.asp)+drawImage' :: (Image, Double, Double, Double, Double) -> Canvas ()+drawImage' = call "drawImage"+-----------------------------------------------------------------------------+-- | [ctx.createImageData(width,height)](https://www.w3schools.com/tags/canvas_createImageData.asp)+createImageData :: (Double, Double) -> Canvas ImageData+createImageData = call "createImageData"+-----------------------------------------------------------------------------+-- | [ctx.getImageData(w,x,y,z)](https://www.w3schools.com/tags/canvas_getImageData.asp)+getImageData :: (Double, Double, Double, Double) -> Canvas ImageData+getImageData = call "getImageData"+-----------------------------------------------------------------------------+-- | [imageData.data\[index\] = 255](https://www.w3schools.com/tags/canvas_imagedata_data.asp)+setImageData :: (ImageData, Int, Double) -> Canvas ()+setImageData (imgData, index, value) = liftIO $ do+ o <- imgData ! ("data" :: MisoString)+ (o <## index) value+-----------------------------------------------------------------------------+-- | [imageData.height](https://www.w3schools.com/tags/canvas_imagedata_height.asp)+height :: ImageData -> Canvas Double+height (ImageData imgData) = liftIO $ do+ fromJSValUnchecked =<< imgData ! ("height" :: MisoString)+-----------------------------------------------------------------------------+-- | [imageData.width](https://www.w3schools.com/tags/canvas_imagedata_width.asp)+width :: ImageData -> Canvas Double+width (ImageData imgData) = liftIO $+ fromJSValUnchecked =<< imgData ! ("width" :: MisoString)+-----------------------------------------------------------------------------+-- | [ctx.putImageData(imageData,x,y)](https://www.w3schools.com/tags/canvas_putImageData.asp)+putImageData :: (ImageData, Double, Double) -> Canvas ()+putImageData = call "putImageData"+-----------------------------------------------------------------------------+-- | [ctx.globalAlpha = 0.2](https://www.w3schools.com/tags/canvas_globalAlpha.asp)+globalAlpha :: Double -> Canvas ()+globalAlpha = set "globalAlpha"+-----------------------------------------------------------------------------+-- | [ctx.clip()](https://www.w3schools.com/tags/canvas_clip.asp)+clip :: () -> Canvas ()+clip = call "clip"+-----------------------------------------------------------------------------+-- | [ctx.save()](https://www.w3schools.com/tags/canvas_save.asp)+save :: () -> Canvas ()+save = call "save"+-----------------------------------------------------------------------------+-- | [ctx.restore()](https://www.w3schools.com/tags/canvas_restore.asp)+restore :: () -> Canvas ()+restore = call "restore"+-----------------------------------------------------------------------------
src/Miso/Concurrent.hs view
@@ -1,40 +1,57 @@+----------------------------------------------------------------------------- {-# LANGUAGE ScopedTypeVariables #-} ----------------------------------------------------------------------------- -- | -- Module : Miso.Concurrent--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable -----------------------------------------------------------------------------module Miso.Concurrent (- Notify (..)- , newNotify- , newEmptyNotify+module Miso.Concurrent+ ( -- ** Synchronization primitives+ Waiter (..)+ , waiter+ , oneshot ) where-+----------------------------------------------------------------------------- import Control.Concurrent---- | Concurrent API for SkipChan implementation-data Notify = Notify {- wait :: IO ()+-----------------------------------------------------------------------------+-- | Synchronization primitive for event loop+data Waiter+ = Waiter+ { wait :: IO ()+ -- ^ Blocks on MVar , notify :: IO ()+ -- ^ Unblocks threads waiting on MVar }---- | Create a new 'Notify'-newNotify :: IO Notify-newNotify = do- mvar <- newMVar ()- pure $ Notify- (takeMVar mvar)- (() <$ do tryPutMVar mvar $! ())---- | Create a new 'Notify'-newEmptyNotify :: IO Notify-newEmptyNotify = do+-----------------------------------------------------------------------------+-- | Creates a new @Waiter@+--+-- Useful for multiple threads to wake-up / notify a single thread running in an+-- infinite loop, waiting for work (e.g. to process an event queue).+--+waiter :: IO Waiter+waiter = do mvar <- newEmptyMVar- pure $ Notify- (takeMVar mvar)- (() <$ do tryPutMVar mvar $! ())-+ pure Waiter+ { wait = takeMVar mvar+ , notify = do+ _ <- tryPutMVar mvar ()+ pure ()+ }+-----------------------------------------------------------------------------+-- | Creates a new @Waiter@+--+-- Useful for a single thread to wake-up multiple threads that are waiting +-- to run a oneshot task (e.g. like forking a thread).+--+oneshot :: IO Waiter+oneshot = do+ mvar <- newEmptyMVar+ pure Waiter+ { wait = readMVar mvar+ , notify = putMVar mvar ()+ }+-----------------------------------------------------------------------------
+ src/Miso/DSL.hs view
@@ -0,0 +1,759 @@+-----------------------------------------------------------------------------+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ <= 865+{-# LANGUAGE UndecidableInstances #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : Miso.DSL+-- Copyright : (C) 2016-2026 David M. Johnson (@dmjio)+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- A JavaScript DSL for interacting with the browser or JS runtime environments.+-----------------------------------------------------------------------------+module Miso.DSL+ ( -- * Classes+ ToJSVal (..)+ , GToJSVal (..)+ , FromJSVal (..)+ , GFromJSVal (..)+ , ToArgs (..)+ , ToObject (..)+ -- * Types+ , JSVal+ , Object (..)+ , Function (..)+ -- * Utils+ , jsg+ , jsg0+ , jsg1+ , jsg2+ , jsg3+ , jsg4+ , jsg5+ , jsgf+ , global+ , (#)+ , setField+ , (<##)+ , (!)+ , listProps+ , call+ , new+ , create+ , createWith+ , setProp+ , getProp+ , eval+ , requestAnimationFrame+ , cancelAnimationFrame+ , freeFunction+ , (!!)+ , isUndefined+ , isNull+ , jsNull+ , syncCallback+ , syncCallback1+ , syncCallback2+ , syncCallback3+ , syncCallback'+ , syncCallback1'+ , syncCallback2'+ , syncCallback3'+ , asyncCallback+ , asyncCallback1+ , asyncCallback2+ , asyncCallback3+ , apply+ ) where+-----------------------------------------------------------------------------+import Control.Applicative+#ifndef VANILLA+import Data.Text (Text)+#endif+import Control.Monad+import Control.Monad.Trans.Maybe+import qualified Data.Map.Strict as M+import Data.Map.Strict (Map)+import GHC.Generics+import GHC.TypeLits+import Data.Kind+import Prelude hiding ((!!))+-----------------------------------------------------------------------------+import Miso.DSL.FFI+import Miso.JSON (Value, fromJSVal_Value, toJSVal_Value)+import Miso.String+-----------------------------------------------------------------------------+-- | A class for marshaling Haskell values into JS+class ToJSVal a where+ toJSVal :: a -> IO JSVal+ default toJSVal :: (Generic a, GToJSVal (Rep a)) => a -> IO JSVal+ toJSVal x = do+ o <- create+ gToJSVal (from x) o+ toJSVal o+-----------------------------------------------------------------------------+class GToJSVal (f :: Type -> Type) where+ gToJSVal :: f a -> Object -> IO ()+-----------------------------------------------------------------------------+instance GToJSVal a => GToJSVal (D1 i a) where+ gToJSVal (M1 x) = gToJSVal x+ {-# INLINE gToJSVal #-}+-----------------------------------------------------------------------------+instance GToJSVal a => GToJSVal (C1 i a) where+ gToJSVal (M1 x) = gToJSVal x+ {-# INLINE gToJSVal #-}+-----------------------------------------------------------------------------+instance (GToJSVal a, GToJSVal b) => GToJSVal (a :*: b) where+ gToJSVal (x :*: y) o = gToJSVal x o >> gToJSVal y o+ {-# INLINE gToJSVal #-}+-----------------------------------------------------------------------------+instance (TypeError ('Text "Sum types unsupported"), GToJSVal a, GToJSVal b) => GToJSVal (a :+: b) where+ gToJSVal = \case+ L1 x -> gToJSVal x+ R1 x -> gToJSVal x+ {-# INLINE gToJSVal #-}+-----------------------------------------------------------------------------+instance (ToJSVal a, Selector s) => GToJSVal (S1 s (K1 i a)) where+ gToJSVal (M1 (K1 x)) o =+ setField o fieldName =<< toJSVal x+ where+ fieldName = ms $ selName (undefined :: S1 s (K1 i a) ())+ {-# INLINE gToJSVal #-}+-----------------------------------------------------------------------------+instance GToJSVal U1 where+ gToJSVal U1 _ = pure ()+ {-# INLINE gToJSVal #-}+-----------------------------------------------------------------------------+instance GToJSVal V1 where+ gToJSVal _ _ = pure ()+ {-# INLINE gToJSVal #-}+-----------------------------------------------------------------------------+instance ToJSVal Bool where+ toJSVal = toJSVal_Bool+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance ToJSVal Double where+ toJSVal = toJSVal_Double+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance ToJSVal Float where+ toJSVal = toJSVal_Float+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance ToJSVal a => ToJSVal (IO a) where+ toJSVal action = toJSVal =<< action+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance ToJSVal () where+ toJSVal () = pure jsNull+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance ToJSVal Char where+ toJSVal = toJSVal_Char+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance ToJSVal Int where+ toJSVal = toJSVal_Int+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance ToJSVal a => ToJSVal (Map MisoString a) where+ toJSVal map_ = do+ o <- create+ forM_ (M.toList map_) $ \(k,v) ->+ setField o k =<< toJSVal v+ toJSVal o+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance FromJSVal a => FromJSVal (Map MisoString a) where+ fromJSVal o = pure <$> do foldM populate M.empty =<< listProps (Object o)+ where+ populate m k = do+ v <- fromJSValUnchecked =<< getProp k (Object o)+ pure (M.insert k v m)+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+instance ToJSVal a => ToObject (Map MisoString a) where+ toObject x = Object <$> toJSVal x+ {-# INLINE toObject #-}+-----------------------------------------------------------------------------+instance ToJSVal a => ToJSVal (Maybe a) where+ toJSVal = \case+ Nothing -> pure jsNull+ Just x -> toJSVal x+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance {-# OVERLAPPABLE #-} FromJSVal a => FromJSVal [a] where+ fromJSVal jsval_ = do+ fromJSVal_List jsval_ >>= \case+ Nothing -> pure Nothing+ Just xs -> sequence <$> mapM fromJSVal xs+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+instance FromJSVal [Char] where+ fromJSVal jsval_ = fmap unpack <$> fromJSVal jsval_+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+instance ToJSVal [Char] where+ toJSVal = toJSVal . toMisoString+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance {-# OVERLAPPABLE #-} ToJSVal a => ToJSVal [a] where+ toJSVal = toJSVal_List <=< mapM toJSVal+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance ToJSVal JSVal where+ toJSVal = pure+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance FromJSVal Value where+ fromJSVal = fromJSVal_Value+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+-- | A class for marshaling JS values into Haskell+class FromJSVal a where+ fromJSVal :: JSVal -> IO (Maybe a)+ default fromJSVal :: (Generic a, GFromJSVal (Rep a)) => JSVal -> IO (Maybe a)+ fromJSVal x = fmap to <$> gFromJSVal (Object x)+ fromJSValUnchecked :: JSVal -> IO a+ fromJSValUnchecked x = do+ fromJSVal x >>= \case+ Nothing -> error "fromJSValUnchecked: failure"+ Just y -> pure y+-----------------------------------------------------------------------------+class GFromJSVal (f :: Type -> Type) where+ gFromJSVal :: Object -> IO (Maybe (f a))+-----------------------------------------------------------------------------+instance GFromJSVal a => GFromJSVal (D1 i a) where+ gFromJSVal o = fmap M1 <$> gFromJSVal o+ {-# INLINE gFromJSVal #-}+-----------------------------------------------------------------------------+instance GFromJSVal a => GFromJSVal (C1 i a) where+ gFromJSVal o = fmap M1 <$> gFromJSVal o+ {-# INLINE gFromJSVal #-}+-----------------------------------------------------------------------------+instance GFromJSVal U1 where+ gFromJSVal _ = pure (Just U1)+ {-# INLINE gFromJSVal #-}+-----------------------------------------------------------------------------+instance GFromJSVal V1 where+ gFromJSVal _ = pure Nothing+ {-# INLINE gFromJSVal #-}+-----------------------------------------------------------------------------+instance (GFromJSVal a, GFromJSVal b) => GFromJSVal (a :*: b) where+ gFromJSVal o = runMaybeT $ (:*:) <$> MaybeT (gFromJSVal o) <*> MaybeT (gFromJSVal o)+ {-# INLINE gFromJSVal #-}+-----------------------------------------------------------------------------+instance (TypeError ('Text "Sum types unsupported"), GFromJSVal a, GFromJSVal b) => GFromJSVal (a :+: b) where+ gFromJSVal o = do+ x <- fmap L1 <$> gFromJSVal o+ case x of+ Nothing -> fmap R1 <$> gFromJSVal o+ Just y -> pure (Just y)+ {-# INLINE gFromJSVal #-}+-----------------------------------------------------------------------------+instance (FromJSVal a, Selector s) => GFromJSVal (S1 s (K1 i a)) where+ gFromJSVal o = fmap (M1 . K1) <$> do fromJSVal =<< getProp (ms name) o+ where+ name = selName (undefined :: S1 s (K1 i a) ())+ {-# INLINE gFromJSVal #-}+-----------------------------------------------------------------------------+instance FromJSVal Int where+ fromJSVal = fromJSVal_Int+ fromJSValUnchecked = fromJSValUnchecked_Int+ {-# INLINE fromJSVal #-}+ {-# INLINE fromJSValUnchecked #-}+-----------------------------------------------------------------------------+instance FromJSVal Char where+ fromJSVal = fromJSVal_Char+ fromJSValUnchecked = fromJSValUnchecked_Char+ {-# INLINE fromJSVal #-}+ {-# INLINE fromJSValUnchecked #-}+-----------------------------------------------------------------------------+instance FromJSVal Float where+ fromJSVal = fromJSVal_Float+ fromJSValUnchecked = fromJSValUnchecked_Float+ {-# INLINE fromJSVal #-}+ {-# INLINE fromJSValUnchecked #-}+-----------------------------------------------------------------------------+instance FromJSVal Double where+ fromJSVal = fromJSVal_Double+ fromJSValUnchecked = fromJSValUnchecked_Double+ {-# INLINE fromJSVal #-}+ {-# INLINE fromJSValUnchecked #-}+-----------------------------------------------------------------------------+instance FromJSVal Text where+ fromJSVal = fromJSVal_Text+ fromJSValUnchecked = fromJSValUnchecked_Text+ {-# INLINE fromJSVal #-}+ {-# INLINE fromJSValUnchecked #-}+-----------------------------------------------------------------------------+instance ToObject Object where+ toObject = pure+ {-# INLINE toObject #-}+-----------------------------------------------------------------------------+instance ToJSVal Value where+ toJSVal = toJSVal_Value+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance ToJSVal Text where+ toJSVal = toJSVal_Text+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance FromJSVal () where+ fromJSVal _ = pure (Just ())+ -- if isUndefined_ffi x || isNull_ffi x+ -- then pure (Just ())+ -- else pure Nothing+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+instance (ToJSVal a, ToJSVal b) => ToJSVal (a,b) where+ toJSVal (y,z) = do+ y_ <- toJSVal y+ z_ <- toJSVal z+ toJSVal_List [ y_, z_ ]+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance (ToJSVal a, ToJSVal b, ToJSVal c) => ToJSVal (a,b,c) where+ toJSVal (x,y,z) = do+ x_ <- toJSVal x+ y_ <- toJSVal y+ z_ <- toJSVal z+ toJSVal_List [ x_, y_, z_ ]+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance (ToJSVal a, ToJSVal b, ToJSVal c, ToJSVal d) => ToJSVal (a,b,c,d) where+ toJSVal (w,x,y,z) = do+ w_ <- toJSVal w+ x_ <- toJSVal x+ y_ <- toJSVal y+ z_ <- toJSVal z+ toJSVal_List [ w_, x_, y_, z_ ]+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance (ToJSVal a, ToJSVal b, ToJSVal c, ToJSVal d, ToJSVal e) => ToJSVal (a,b,c,d,e) where+ toJSVal (v,w,x,y,z) = do+ v_ <- toJSVal v+ w_ <- toJSVal w+ x_ <- toJSVal x+ y_ <- toJSVal y+ z_ <- toJSVal z+ toJSVal_List [ v_, w_, x_, y_, z_ ]+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance (ToJSVal a, ToJSVal b, ToJSVal c, ToJSVal d, ToJSVal e, ToJSVal f) => ToJSVal (a,b,c,d,e,f) where+ toJSVal (u,v,w,x,y,z) = do+ u_ <- toJSVal u+ v_ <- toJSVal v+ w_ <- toJSVal w+ x_ <- toJSVal x+ y_ <- toJSVal y+ z_ <- toJSVal z+ toJSVal_List [ u_, v_, w_, x_, y_, z_ ]+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+-- | Retrieves a field from globalThis+jsg :: MisoString -> IO JSVal+jsg key = global ! key+{-# INLINABLE jsg #-}+-----------------------------------------------------------------------------+-- | Invokes a function with a specified argument list+jsgf :: ToArgs args => MisoString -> args -> IO JSVal+jsgf name = global # name+{-# INLINABLE jsgf #-}+-----------------------------------------------------------------------------+-- | Invokes a function with no argument+jsg0 :: MisoString -> IO JSVal+jsg0 name = jsgf name ([] :: [JSVal])+{-# INLINABLE jsg0 #-}+-----------------------------------------------------------------------------+-- | Invokes a function with 1 argument+jsg1 :: ToJSVal arg => MisoString -> arg -> IO JSVal+jsg1 name arg = jsgf name [arg]+{-# INLINABLE jsg1 #-}+-----------------------------------------------------------------------------+-- | Invokes a function with 2 arguments+jsg2 :: (ToJSVal arg1, ToJSVal arg2) => MisoString -> arg1 -> arg2 -> IO JSVal+jsg2 name arg1 arg2 = do+ arg1_ <- toJSVal arg1+ arg2_ <- toJSVal arg2+ jsgf name [arg1_, arg2_]+{-# INLINABLE jsg2 #-}+-----------------------------------------------------------------------------+-- | Invokes a function with 3 arguments+jsg3 :: (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3)+ => MisoString+ -> arg1+ -> arg2+ -> arg3+ -> IO JSVal+jsg3 name arg1 arg2 arg3 = do+ arg1_ <- toJSVal arg1+ arg2_ <- toJSVal arg2+ arg3_ <- toJSVal arg3+ jsgf name [arg1_, arg2_, arg3_]+{-# INLINABLE jsg3 #-}+-----------------------------------------------------------------------------+-- | Invokes a function with 4 arguments+jsg4 :: (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4)+ => MisoString+ -> arg1+ -> arg2+ -> arg3+ -> arg4+ -> IO JSVal+jsg4 name arg1 arg2 arg3 arg4 = do+ arg1_ <- toJSVal arg1+ arg2_ <- toJSVal arg2+ arg3_ <- toJSVal arg3+ arg4_ <- toJSVal arg4+ jsgf name [arg1_, arg2_, arg3_, arg4_]+{-# INLINABLE jsg4 #-}+-----------------------------------------------------------------------------+-- | Invokes a function with 5 arguments+jsg5 :: (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4, ToJSVal arg5)+ => MisoString+ -> arg1+ -> arg2+ -> arg3+ -> arg4+ -> arg5+ -> IO JSVal+jsg5 name arg1 arg2 arg3 arg4 arg5 = do+ arg1_ <- toJSVal arg1+ arg2_ <- toJSVal arg2+ arg3_ <- toJSVal arg3+ arg4_ <- toJSVal arg4+ arg5_ <- toJSVal arg5+ jsgf name [arg1_, arg2_, arg3_, arg4_, arg5_]+{-# INLINABLE jsg5 #-}+-----------------------------------------------------------------------------+-- | Sets a field on an Object at a specified field+setField :: (ToObject o, ToJSVal v) => o -> MisoString -> v -> IO ()+setField o k v = do+ o' <- toJSVal =<< toObject o+ v' <- toJSVal v+ setProp_ffi k v' o'+{-# INLINABLE setField #-}+-----------------------------------------------------------------------------+-- | Sets a field on an Object at a specified index+infixr 1 <##+(<##) :: (ToObject o, ToJSVal v) => o -> Int -> v -> IO ()+(<##) o k v = do+ o' <- toJSVal =<< toObject o+ v' <- toJSVal v+ setPropIndex_ffi k v' o'+{-# INLINABLE (<##) #-}+-----------------------------------------------------------------------------+-- | Retrieves a property from an Object+(!) :: ToObject o => o -> MisoString -> IO JSVal+(!) = flip getProp+{-# INLINABLE (!) #-}+-----------------------------------------------------------------------------+-- | Lists the properties on a JS Object.+listProps :: Object -> IO [MisoString]+listProps (Object jsval) = do+ keys <- fromJSValUnchecked =<< listProps_ffi jsval+ forM keys fromJSValUnchecked+{-# INLINABLE listProps #-}+-----------------------------------------------------------------------------+-- | Calls a JS function on an t'Object' at a field with specified arguments.+call :: (ToObject obj, ToObject this, ToArgs args) => obj -> this -> args -> IO JSVal+call o this args = do+ o' <- toJSVal =<< toObject o+ this' <- toJSVal =<< toObject this+ args' <- toJSVal =<< toArgs args+ invokeFunction o' this' args'+{-# INLINABLE call #-}+-----------------------------------------------------------------------------+-- | Calls a JS function on an t'Object' at a field with specified arguments.+infixr 2 #+(#) :: (ToObject object, ToArgs args) => object -> MisoString -> args -> IO JSVal+(#) o k args = do+ o' <- toJSVal =<< toObject o+ func <- getProp_ffi k o'+ args' <- toJSVal =<< toArgs args+ invokeFunction func o' args'+{-# INLINABLE (#) #-}+-----------------------------------------------------------------------------+apply :: (FromJSVal a, ToArgs args) => Function -> args -> IO a+apply (Function func) args = do+ o <- toJSVal global+ fromJSValUnchecked =<< do+ invokeFunction func o =<<+ toJSVal (toArgs args)+{-# INLINABLE apply #-}+-----------------------------------------------------------------------------+-- | Instantiates a new JS t'Object'.+new :: (ToObject constructor, ToArgs args) => constructor -> args -> IO JSVal+new constr args = do+ obj <- toJSVal =<< toObject constr+ argv <- toJSVal =<< toArgs args+ new_ffi obj argv+{-# INLINABLE new #-}+-----------------------------------------------------------------------------+-- | Creates a new JS t'Object'+create :: IO Object+create = Object <$> create_ffi+{-# INLINABLE create #-}+-----------------------------------------------------------------------------+-- | Creates a new JS t'Object' populated with key-value pairs specified+-- in the list. Meant for use with 'inline' JS functionality.+--+-- @+-- update = \case+-- Highlight domRef -> do+-- 3 <- inline "hljs.highlight(domRef); return 3;" =<<+-- createWith [ "domRef" =: domRef ]+-- pure ()+-- @+--+createWith :: ToJSVal val => [(MisoString, val)] -> IO Object+createWith kvs = do+ o <- create+ forM_ kvs $ \(k,v) ->+ flip (setProp k) o =<< toJSVal v+ pure o+{-# INLINABLE createWith #-}+-----------------------------------------------------------------------------+-- | Sets a property on a JS t'Object'+setProp :: ToJSVal val => MisoString -> val -> Object -> IO ()+setProp k v (Object o) = flip (setProp_ffi k) o =<< toJSVal v+{-# INLINABLE setProp #-}+-----------------------------------------------------------------------------+-- | Retrieves a property from a JS t'Object'+getProp :: ToObject o => MisoString -> o -> IO JSVal+getProp k v = getProp_ffi k =<< toJSVal (toObject v)+{-# INLINABLE getProp #-}+-----------------------------------------------------------------------------+-- | Dynamically evaluates a JS string. See [eval](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval)+--+-- `eval()` is slower (not subject to JS engine optimizations) and also+-- has security vulnerabilities (can alter other local variables).+--+-- Consider using the more performant and secure (isolated) `inline` function.+--+eval :: MisoString -> IO JSVal+eval = eval_ffi+{-# INLINABLE eval #-}+-----------------------------------------------------------------------------+instance FromJSVal Bool where+ fromJSVal = fromJSVal_Bool+ fromJSValUnchecked = fromJSValUnchecked_Bool+ {-# INLINE fromJSVal #-}+ {-# INLINE fromJSValUnchecked #-}+-----------------------------------------------------------------------------+instance FromJSVal JSVal where+ fromJSVal = pure . Just+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+instance FromJSVal a => FromJSVal (Maybe a) where+ fromJSVal x = fromJSVal_Maybe x >>= \case+ Nothing -> pure Nothing+ Just Nothing -> pure (Just Nothing)+ Just (Just y) -> fmap Just <$> fromJSVal y+ fromJSValUnchecked x = fromJSValUnchecked_Maybe x >>= \case+ Nothing -> pure Nothing+ Just y -> Just <$> fromJSValUnchecked y+ {-# INLINE fromJSVal #-}+ {-# INLINE fromJSValUnchecked #-}+-----------------------------------------------------------------------------+-- | A class for creating arguments to a JS function+class ToArgs args where+ toArgs :: args -> IO [JSVal]+-----------------------------------------------------------------------------+instance ToArgs Double where+ toArgs x = (:[]) <$> toJSVal x+ {-# INLINE toArgs #-}+-----------------------------------------------------------------------------+instance ToArgs JSVal where+ toArgs val = pure [val]+ {-# INLINE toArgs #-}+-----------------------------------------------------------------------------+instance ToObject JSVal where+ toObject = pure . Object+ {-# INLINE toObject #-}+-----------------------------------------------------------------------------+-- | A class for creating JS objects.+class ToObject a where+ toObject :: a -> IO Object+ default toObject :: (Generic a, GToJSVal (Rep a)) => a -> IO Object+ toObject x = do+ o <- create+ gToJSVal (from x) o+ pure o+-----------------------------------------------------------------------------+instance ToJSVal a => ToObject (IO a) where+ toObject action = Object <$> (toJSVal =<< action)+ {-# INLINE toObject #-}+-----------------------------------------------------------------------------+instance ToArgs MisoString where+ toArgs arg = (:[]) <$> toJSVal arg+ {-# INLINE toArgs #-}+----------------------------------------------------------------------------+#ifndef VANILLA+----------------------------------------------------------------------------+instance ToJSVal MisoString where+ toJSVal = toJSVal_JSString+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+instance FromJSVal MisoString where+ fromJSVal = fromJSVal_JSString+ {-# INLINE fromJSVal #-}+----------------------------------------------------------------------------+#endif+----------------------------------------------------------------------------+instance ToJSVal arg => ToArgs [arg] where+ toArgs = mapM toJSVal+ {-# INLINE toArgs #-}+----------------------------------------------------------------------------+instance ToArgs () where+ toArgs _ = pure []+ {-# INLINE toArgs #-}+----------------------------------------------------------------------------+instance ToArgs Int where+ toArgs k = (:[]) <$> toJSVal k+ {-# INLINE toArgs #-}+-----------------------------------------------------------------------------+instance ToArgs Function where+ toArgs k = (:[]) <$> toJSVal k+ {-# INLINE toArgs #-}+-----------------------------------------------------------------------------+instance ToArgs Bool where+ toArgs k = (:[]) <$> toJSVal k+ {-# INLINE toArgs #-}+-----------------------------------------------------------------------------+instance ToArgs Object where+ toArgs k = (:[]) <$> toJSVal k+ {-# INLINE toArgs #-}+-----------------------------------------------------------------------------+instance ToArgs args => ToArgs (Maybe args) where+ toArgs (Just args) = toArgs args+ toArgs Nothing = pure []+ {-# INLINE toArgs #-}+----------------------------------------------------------------------------+instance (ToJSVal arg1, ToJSVal arg2) => ToArgs (arg1, arg2) where+ toArgs (arg1, arg2) = do+ rarg1 <- toJSVal arg1+ rarg2 <- toJSVal arg2+ return [rarg1, rarg2]+ {-# INLINE toArgs #-}+----------------------------------------------------------------------------+instance (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3) => ToArgs (arg1, arg2, arg3) where+ toArgs (arg1, arg2, arg3) = do+ rarg1 <- toJSVal arg1+ rarg2 <- toJSVal arg2+ rarg3 <- toJSVal arg3+ return [rarg1, rarg2, rarg3]+ {-# INLINE toArgs #-}+----------------------------------------------------------------------------+instance (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4) => ToArgs (arg1, arg2, arg3, arg4) where+ toArgs (arg1, arg2, arg3, arg4) = do+ rarg1 <- toJSVal arg1+ rarg2 <- toJSVal arg2+ rarg3 <- toJSVal arg3+ rarg4 <- toJSVal arg4+ return [rarg1, rarg2, rarg3, rarg4]+ {-# INLINE toArgs #-}+----------------------------------------------------------------------------+instance (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4, ToJSVal arg5) => ToArgs (arg1, arg2, arg3, arg4, arg5) where+ toArgs (arg1, arg2, arg3, arg4, arg5) = do+ rarg1 <- toJSVal arg1+ rarg2 <- toJSVal arg2+ rarg3 <- toJSVal arg3+ rarg4 <- toJSVal arg4+ rarg5 <- toJSVal arg5+ return [rarg1, rarg2, rarg3, rarg4, rarg5]+ {-# INLINE toArgs #-}+----------------------------------------------------------------------------+instance (ToJSVal arg1, ToJSVal arg2, ToJSVal arg3, ToJSVal arg4, ToJSVal arg5, ToJSVal arg6) => ToArgs (arg1, arg2, arg3, arg4, arg5, arg6) where+ toArgs (arg1, arg2, arg3, arg4, arg5, arg6) = do+ rarg1 <- toJSVal arg1+ rarg2 <- toJSVal arg2+ rarg3 <- toJSVal arg3+ rarg4 <- toJSVal arg4+ rarg5 <- toJSVal arg5+ rarg6 <- toJSVal arg6+ return [rarg1, rarg2, rarg3, rarg4, rarg5, rarg6]+ {-# INLINE toArgs #-}+----------------------------------------------------------------------------+-- | Frees references to a callback+freeFunction :: Function -> IO ()+freeFunction (Function x) = freeFunction_ffi x+{-# INLINABLE freeFunction #-}+-----------------------------------------------------------------------------+instance FromJSVal Function where+ fromJSVal = pure . Just . Function+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+instance FromJSVal Object where+ fromJSVal = pure . Just . Object+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+-- | Lookup a property based on its index+(!!) :: ToObject object => object -> Int -> IO JSVal+(!!) o k = getPropIndex_ffi k =<< toJSVal =<< toObject o+{-# INLINABLE (!!) #-}+-----------------------------------------------------------------------------+-- | Checks if a t'JSVal' is undefined+isUndefined :: ToJSVal val => val -> IO Bool+isUndefined val = isUndefined_ffi <$> toJSVal val+{-# INLINABLE isUndefined #-}+-----------------------------------------------------------------------------+-- | Checks if a t'JSVal' is null+isNull :: ToJSVal val => val -> IO Bool+isNull val = isNull_ffi <$> toJSVal val+{-# INLINABLE isNull #-}+-----------------------------------------------------------------------------+-- | A JS Object+newtype Object = Object { unObject :: JSVal } deriving newtype (ToJSVal, Eq)+-----------------------------------------------------------------------------+-- | A JS Functionn+newtype Function = Function { unFunction :: JSVal } deriving newtype (ToJSVal, Eq)+-----------------------------------------------------------------------------+instance (FromJSVal a, FromJSVal b) => FromJSVal (a,b) where+ fromJSVal r = runMaybeT $ (,) <$> jf r 0 <*> jf r 1+ {-# INLINE fromJSVal #-}+instance (FromJSVal a, FromJSVal b, FromJSVal c) => FromJSVal (a,b,c) where+ fromJSVal r = runMaybeT $ (,,) <$> jf r 0 <*> jf r 1 <*> jf r 2+ {-# INLINE fromJSVal #-}+instance (FromJSVal a, FromJSVal b, FromJSVal c, FromJSVal d) => FromJSVal (a,b,c,d) where+ fromJSVal r = runMaybeT $ (,,,) <$> jf r 0 <*> jf r 1 <*> jf r 2 <*> jf r 3+ {-# INLINE fromJSVal #-}+instance (FromJSVal a, FromJSVal b, FromJSVal c, FromJSVal d, FromJSVal e) => FromJSVal (a,b,c,d,e) where+ fromJSVal r = runMaybeT $ (,,,,) <$> jf r 0 <*> jf r 1 <*> jf r 2 <*> jf r 3 <*> jf r 4+ {-# INLINE fromJSVal #-}+instance (FromJSVal a, FromJSVal b, FromJSVal c, FromJSVal d, FromJSVal e, FromJSVal f) => FromJSVal (a,b,c,d,e,f) where+ fromJSVal r = runMaybeT $ (,,,,,) <$> jf r 0 <*> jf r 1 <*> jf r 2 <*> jf r 3 <*> jf r 4 <*> jf r 5+ {-# INLINE fromJSVal #-}+instance (FromJSVal a, FromJSVal b, FromJSVal c, FromJSVal d, FromJSVal e, FromJSVal f, FromJSVal g) => FromJSVal (a,b,c,d,e,f,g) where+ fromJSVal r = runMaybeT $ (,,,,,,) <$> jf r 0 <*> jf r 1 <*> jf r 2 <*> jf r 3 <*> jf r 4 <*> jf r 5 <*> jf r 6+ {-# INLINE fromJSVal #-}+instance (FromJSVal a, FromJSVal b, FromJSVal c, FromJSVal d, FromJSVal e, FromJSVal f, FromJSVal g, FromJSVal h) => FromJSVal (a,b,c,d,e,f,g,h) where+ fromJSVal r = runMaybeT $ (,,,,,,,) <$> jf r 0 <*> jf r 1 <*> jf r 2 <*> jf r 3 <*> jf r 4 <*> jf r 5 <*> jf r 6 <*> jf r 7+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+jf :: FromJSVal a => JSVal -> Int -> MaybeT IO a+{-# INLINE jf #-}+jf r n = MaybeT $ do+ x <- getPropIndex_ffi n r+ if isUndefined_ffi r+ then return Nothing+ else fromJSVal x+-----------------------------------------------------------------------------
+ src/Miso/Data/Array.hs view
@@ -0,0 +1,147 @@+-----------------------------------------------------------------------------+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Data.Array+-- Copyright : (C) 2016-2026 David M. Johnson (@dmjio)+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- Mutable 'Array' data structure in 'IO'.+--+-- A JavaScript [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array). This is a convenience for manipulating JavaScript data structures from Haskell.+--+-- We recommend using this module qualified.+--+-- > import qualified Miso.Data.Array as M+--+-----------------------------------------------------------------------------+module Miso.Data.Array+ ( -- * Type+ Array+ -- * Construction+ , new+ , fromList+ -- * Deconstruction+ , toList+ -- * Operations+ , insert+ , push+ , member+ , size+ , splice+ , singleton+ , pop+ , shift+ , unshift+ , null+ , lookup+ , (!?)+ , reverse+ ) where+-----------------------------------------------------------------------------+import Control.Monad (void, forM, forM_)+import Prelude hiding (lookup, null, reverse)+-----------------------------------------------------------------------------+import Miso.DSL (jsg, JSVal, ToObject, ToJSVal, FromJSVal, (!))+import qualified Miso.DSL as DSL+import Miso.FFI (callFunction)+import Miso.String (ms, unpack)+-----------------------------------------------------------------------------+newtype Array value = Array JSVal deriving (FromJSVal, ToJSVal, ToObject)+-----------------------------------------------------------------------------+-- | Constructs a new JS [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) in t'IO'.+--+new :: IO (Array value)+new = Array <$> DSL.new (jsg "Array") ([] :: [JSVal])+-----------------------------------------------------------------------------+-- | Inserts a value into the t'Array' by value.+insert :: ToJSVal value => Int -> value -> Array value -> IO ()+insert key value (Array m) = do+ _ <- (DSL.Object m) DSL.<## key $ value+ pure ()+-----------------------------------------------------------------------------+-- | Inserts a value into the t'Array' by value.+push :: ToJSVal value => value -> Array value -> IO ()+push value (Array m) = do+ _ <- callFunction m "push" [value]+ pure ()+-----------------------------------------------------------------------------+-- | Look up a value in the array by key.+lookup :: FromJSVal value => Int -> Array value -> IO (Maybe value)+lookup key m = DSL.fromJSValUnchecked =<< m DSL.!! key+-----------------------------------------------------------------------------+-- | Look up a value in the array by key.+(!?) :: FromJSVal value => Int -> Array value -> IO value+(!?) key m =+ lookup key m >>= \case+ Nothing ->+ error ("(!?) index out of bounds: " <> unpack (ms key))+ Just value ->+ pure value+-----------------------------------------------------------------------------+-- | Return the size of t'Array'.+size :: Array value -> IO Int+size (Array m) = DSL.fromJSValUnchecked =<< m ! "length"+-----------------------------------------------------------------------------+-- | Return the null of t'Array'.+null :: Array value -> IO Bool+null m = (== 0) <$> size m+-----------------------------------------------------------------------------+-- | Checks existence of 'value' in t'Array', returns t'Bool.+member :: ToJSVal value => value -> Array value -> IO Bool+member value (Array m) = DSL.fromJSValUnchecked =<< callFunction m "includes" =<< DSL.toJSVal value+-----------------------------------------------------------------------------+-- | Splices an array. See [splice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice).+splice :: ToJSVal value => Int -> Int -> [value] -> Array value -> IO (Array value)+splice start deleteCount xs (Array m) = do+ s <- DSL.toJSVal start+ d <- DSL.toJSVal deleteCount+ args <- mapM DSL.toJSVal xs+ Array <$> do callFunction m "splice" $ [s,d] ++ args+-----------------------------------------------------------------------------+-- | Construct a t'Array' from a list of value value pairs.+fromList :: ToJSVal value => [value] -> IO (Array value)+fromList xs = do+ m <- new+ forM_ (zip [0..] xs) $ \(k,v) ->+ insert k v m+ pure m+-----------------------------------------------------------------------------+-- | Converts an t'Array' to a list.+toList :: FromJSVal value => Array value -> IO [value]+toList m = do+ len <- subtract 1 <$> size m+ forM [0..len] (!? m)+-----------------------------------------------------------------------------+-- | Creates a new Array with a single element.+--+singleton :: ToJSVal a => a -> IO (Array a)+singleton x = fromList [x]+-----------------------------------------------------------------------------+-- | Removes the last element from an array and returns it.+--+-- Returns 'Nothing' if the t'Array' is empty.+--+pop :: FromJSVal a => Array a -> IO (Maybe a)+pop (Array arr) = DSL.fromJSValUnchecked =<< callFunction arr "pop" ([] :: [JSVal])+-----------------------------------------------------------------------------+-- | Removes the first element from an array and returns it.+--+shift :: FromJSVal a => Array a -> IO (Maybe a)+shift (Array arr) = DSL.fromJSValUnchecked =<< callFunction arr "shift" ([] :: [JSVal])+-----------------------------------------------------------------------------+-- | Adds one or more elements to the beginning of an array.+--+unshift :: ToJSVal a => a -> Array a -> IO Int+unshift x (Array arr) = DSL.fromJSValUnchecked =<< callFunction arr "unshift" [x]+-----------------------------------------------------------------------------+-- | Reverses an array in-place.+--+reverse :: Array a -> IO ()+reverse (Array arr) = void $ callFunction arr "reverse" ([] :: [JSVal])+-----------------------------------------------------------------------------
+ src/Miso/Data/Map.hs view
@@ -0,0 +1,84 @@+-----------------------------------------------------------------------------+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Data.Map+-- Copyright : (C) 2016-2026 David M. Johnson (@dmjio)+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- Mutable 'Map' data structure in 'IO'.+--+-- A JavaScript [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map). This is a convenience for manipulating JavaScript data structures from Haskell.+--+-- We recommend using this module qualified.+--+-- > import qualified Miso.Data.Map as M+--+-----------------------------------------------------------------------------+module Miso.Data.Map+ ( -- * Type+ Map+ -- * Construction+ , new+ , fromList+ -- * Operations+ , insert+ , lookup+ , clear+ , size+ , has+ , delete+ ) where+-----------------------------------------------------------------------------+import Control.Monad (void, forM_)+import Prelude hiding (lookup)+-----------------------------------------------------------------------------+import Miso.DSL (jsg, JSVal, ToJSVal, FromJSVal, (!))+import qualified Miso.DSL as DSL+import Miso.FFI (callFunction)+-----------------------------------------------------------------------------+newtype Map key value = Map JSVal deriving (FromJSVal, ToJSVal)+-----------------------------------------------------------------------------+-- | Constructs a new JS [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) in t'IO'.+--+new :: IO (Map key value)+new = Map <$> DSL.new (jsg "Map") ([] :: [JSVal])+-----------------------------------------------------------------------------+-- | Inserts a value into the t'Map' by key.+insert :: (ToJSVal key, ToJSVal value) => key -> value -> Map key value -> IO ()+insert key value (Map m) = do+ _ <- callFunction m "set" (key, value)+ pure ()+-----------------------------------------------------------------------------+-- | Finds a value in the t'Map' by key.+lookup :: (ToJSVal key, FromJSVal value) => key -> Map key value -> IO (Maybe value)+lookup key (Map m) = DSL.fromJSValUnchecked =<< callFunction m "get" =<< DSL.toJSVal key+-----------------------------------------------------------------------------+-- | Empties the t'Map'.+clear :: Map key value -> IO ()+clear (Map m) = void (callFunction m "clear" ())+-----------------------------------------------------------------------------+-- | Return the size of t'Map'.+size :: Map key value -> IO Int+size (Map m) = DSL.fromJSValUnchecked =<< m ! "size"+-----------------------------------------------------------------------------+-- | Checks existence of a value by 'key', returns t'Bool.+has :: ToJSVal key => key -> Map key value -> IO Bool+has key (Map m) = DSL.fromJSValUnchecked =<< callFunction m "has" =<< DSL.toJSVal key+-----------------------------------------------------------------------------+-- | Removes an entry from a list, returns if the value was removed as t'Bool'.+delete :: ToJSVal key => key -> Map key value -> IO Bool+delete key (Map m) = DSL.fromJSValUnchecked =<< callFunction m "delete" =<< DSL.toJSVal key+-----------------------------------------------------------------------------+-- | Construct a t'Map' from a list of key value pairs.+fromList :: (ToJSVal key, ToJSVal value) => [(key, value)] -> IO (Map key value)+fromList xs = do+ m <- new+ forM_ xs $ \(k,v) ->+ insert k v m+ pure m+-----------------------------------------------------------------------------
+ src/Miso/Data/Set.hs view
@@ -0,0 +1,112 @@+-----------------------------------------------------------------------------+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Data.Set+-- Copyright : (C) 2016-2026 David M. Johnson (@dmjio)+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- Mutable 'Set' data structure in 'IO'.+--+-- A JavaScript [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set). This is a convenience for manipulating JavaScript data structures from Haskell.+--+-- We recommend using this module qualified.+--+-- > import qualified Miso.Data.Set as M+--+-----------------------------------------------------------------------------+module Miso.Data.Set+ ( -- * Type+ Set+ -- * Construction+ , new+ , fromList+ -- * Operations+ , insert+ , member+ , clear+ , size+ , delete+ , union+ , intersection+ , difference+ , isSubset+ , isSuperset+ , isDisjoint+ ) where+-----------------------------------------------------------------------------+import Control.Monad (void, forM_)+import Prelude hiding (lookup)+-----------------------------------------------------------------------------+import Miso.DSL (jsg, JSVal, ToJSVal, FromJSVal, (!))+import qualified Miso.DSL as DSL+import Miso.FFI (callFunction)+-----------------------------------------------------------------------------+newtype Set key = Set JSVal deriving (FromJSVal, ToJSVal)+-----------------------------------------------------------------------------+-- | Constructs a new JS [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) in t'IO'.+--+new :: IO (Set key)+new = Set <$> DSL.new (jsg "Set") ([] :: [JSVal])+-----------------------------------------------------------------------------+-- | Inserts a value into the t'Set' by key.+insert :: ToJSVal key => key -> Set key -> IO ()+insert key (Set m) = do+ _ <- callFunction m "add" [key]+ pure ()+-----------------------------------------------------------------------------+-- | Empties the t'Set'.+clear :: Set key -> IO ()+clear (Set m) = void (callFunction m "clear" ())+-----------------------------------------------------------------------------+-- | Return the size of t'Set'.+size :: Set key -> IO Int+size (Set m) = DSL.fromJSValUnchecked =<< m ! "size"+-----------------------------------------------------------------------------+-- | Checks existence of 'key' in t'Set', returns t'Bool.+member :: ToJSVal key => key -> Set key -> IO Bool+member key (Set m) = DSL.fromJSValUnchecked =<< callFunction m "has" =<< DSL.toJSVal key+-----------------------------------------------------------------------------+-- | Removes an entry from a list, returns if the value was removed as t'Bool'.+delete :: ToJSVal key => key -> Set key -> IO Bool+delete key (Set m) = DSL.fromJSValUnchecked =<< callFunction m "delete" =<< DSL.toJSVal key+-----------------------------------------------------------------------------+-- | Construct a t'Set' from a list of key value pairs.+fromList :: ToJSVal key => [key] -> IO (Set key)+fromList xs = do+ m <- new+ forM_ xs $ \k ->+ insert k m+ pure m+-----------------------------------------------------------------------------+-- | The union of two t'Set'+union :: ToJSVal key => Set key -> Set key -> IO (Set key)+union (Set x) (Set y) = Set <$> callFunction x "union" [y]+-----------------------------------------------------------------------------+-- | The intersection of two t'Set'+intersection :: ToJSVal key => Set key -> Set key -> IO (Set key)+intersection (Set x) (Set y) = Set <$> callFunction x "intersection" [y]+-----------------------------------------------------------------------------+-- | The symmetric difference of two t'Set'+difference :: ToJSVal key => Set key -> Set key -> IO (Set key)+difference (Set x) (Set y) = Set <$> callFunction x "symmetricDifference" [y]+-----------------------------------------------------------------------------+-- | Checks if one t'Set' is a subset of another t'Set'+isSubset :: ToJSVal key => Set key -> Set key -> IO Bool+isSubset (Set x) (Set y) = DSL.fromJSValUnchecked =<<+ callFunction x "isSubsetOf" [y]+-----------------------------------------------------------------------------+-- | Checks if one t'Set' is a superset of another t'Set'+isSuperset :: ToJSVal key => Set key -> Set key -> IO Bool+isSuperset (Set x) (Set y) = DSL.fromJSValUnchecked =<<+ callFunction x "isSupersetOf" [y]+-----------------------------------------------------------------------------+-- | Checks if one t'Set' is disjoint from another t'Set'+isDisjoint :: ToJSVal key => Set key -> Set key -> IO Bool+isDisjoint (Set x) (Set y) = DSL.fromJSValUnchecked =<<+ callFunction x "isDisjointFrom" [y]+-----------------------------------------------------------------------------
+ src/Miso/Date.hs view
@@ -0,0 +1,367 @@+-----------------------------------------------------------------------------+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Date+-- Copyright : (C) 2016-2026 David M. Johnson (@dmjio)+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- Mutable 'Date' data structure in 'IO'.+--+-- A JavaScript [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date). This is a convenience for manipulating JavaScript data structures from Haskell.+--+-- We recommend using this module qualified.+--+-- > import qualified Miso.Date as D+--+-----------------------------------------------------------------------------+module Miso.Date+ ( -- * Type+ Date+ -- * Construction+ , new+ -- * Conversion+ , toDateString+ , toISOString+ , toJSON+ , toLocaleDateString+ , toLocaleString+ , toLocaleTimeString+ , toString+ , toTimeString+ , toUTCString+ , valueOf+ -- * Getters+ , getDate+ , getDay+ , getFullYear+ , getHours+ , getMilliseconds+ , getMinutes+ , getMonth+ , getSeconds+ , getTime+ , getTimezoneOffset+ , getUTCDate+ , getUTCDay+ , getUTCFullYear+ , getUTCHours+ , getUTCMilliseconds+ , getUTCMinutes+ , getUTCMonth+ , getUTCSeconds+ -- * Setters+ , setDate+ , setFullYear+ , setHours+ , setMilliseconds+ , setMinutes+ , setMonth+ , setSeconds+ , setTime+ , setUTCDate+ , setUTCFullYear+ , setUTCHours+ , setUTCMilliseconds+ , setUTCMinutes+ , setUTCMonth+ , setUTCSeconds+ ) where+-----------------------------------------------------------------------------+import Data.Maybe (catMaybes)+-----------------------------------------------------------------------------+import Miso.DSL (jsg, JSVal, ToJSVal, FromJSVal, ToObject)+import qualified Miso.DSL as DSL+import Miso.FFI (callFunction)+import Miso.String (MisoString)+-----------------------------------------------------------------------------+newtype Date = Date JSVal deriving (FromJSVal, ToJSVal, ToObject, Eq)+-----------------------------------------------------------------------------+-- | Constructs a new JS [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) in t'IO'.+--+new :: IO Date+new = Date <$> DSL.new (jsg "Date") ([] :: [JSVal])+-----------------------------------------------------------------------------+call0 :: FromJSVal a => Date -> MisoString -> IO a+call0 (Date d) name = DSL.fromJSValUnchecked =<< callFunction d name ([] :: [JSVal])+-----------------------------------------------------------------------------+callArgs :: FromJSVal a => Date -> MisoString -> [JSVal] -> IO a+callArgs (Date d) name args = DSL.fromJSValUnchecked =<< callFunction d name args+-----------------------------------------------------------------------------+-- | Returns a human-readable date string.+--+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toDateString>+--+toDateString :: Date -> IO MisoString+toDateString date = call0 date "toDateString"+-----------------------------------------------------------------------------+-- | Returns an ISO 8601 string.+--+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString>+--+toISOString :: Date -> IO MisoString+toISOString date = call0 date "toISOString"+-----------------------------------------------------------------------------+-- | Returns the JSON representation of the date.+--+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toJSON>+--+toJSON :: Date -> IO MisoString+toJSON date = call0 date "toJSON"+-----------------------------------------------------------------------------+-- | Returns a locale-sensitive date string.+--+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString>+--+toLocaleDateString :: Date -> IO MisoString+toLocaleDateString date = call0 date "toLocaleDateString"+-----------------------------------------------------------------------------+-- | Returns a locale-sensitive date and time string.+--+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString>+--+toLocaleString :: Date -> IO MisoString+toLocaleString date = call0 date "toLocaleString"+-----------------------------------------------------------------------------+-- | Returns a locale-sensitive time string.+--+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString>+--+toLocaleTimeString :: Date -> IO MisoString+toLocaleTimeString date = call0 date "toLocaleTimeString"+-----------------------------------------------------------------------------+-- | Returns the full date string.+--+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toString>+--+toString :: Date -> IO MisoString+toString date = call0 date "toString"+-----------------------------------------------------------------------------+-- | Returns a time string.+--+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toTimeString>+--+toTimeString :: Date -> IO MisoString+toTimeString date = call0 date "toTimeString"+-----------------------------------------------------------------------------+-- | Returns a UTC string.+--+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toUTCString>+--+toUTCString :: Date -> IO MisoString+toUTCString date = call0 date "toUTCString"+-----------------------------------------------------------------------------+-- | Returns the primitive value (milliseconds since epoch).+--+-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/valueOf>+--+valueOf :: Date -> IO Double+valueOf date = call0 date "valueOf"+-----------------------------------------------------------------------------+-- | Returns the day of the month.+--+getDate :: Date -> IO Int+getDate date = call0 date "getDate"+-----------------------------------------------------------------------------+-- | Returns the day of the week.+--+getDay :: Date -> IO Int+getDay date = call0 date "getDay"+-----------------------------------------------------------------------------+-- | Returns the full year.+--+getFullYear :: Date -> IO Int+getFullYear date = call0 date "getFullYear"+-----------------------------------------------------------------------------+-- | Returns the hour.+--+getHours :: Date -> IO Int+getHours date = call0 date "getHours"+-----------------------------------------------------------------------------+-- | Returns the milliseconds.+--+getMilliseconds :: Date -> IO Int+getMilliseconds date = call0 date "getMilliseconds"+-----------------------------------------------------------------------------+-- | Returns the minutes.+--+getMinutes :: Date -> IO Int+getMinutes date = call0 date "getMinutes"+-----------------------------------------------------------------------------+-- | Returns the month (0-11).+--+getMonth :: Date -> IO Int+getMonth date = call0 date "getMonth"+-----------------------------------------------------------------------------+-- | Returns the seconds.+--+getSeconds :: Date -> IO Int+getSeconds date = call0 date "getSeconds"+-----------------------------------------------------------------------------+-- | Returns milliseconds since epoch.+--+getTime :: Date -> IO Double+getTime date = call0 date "getTime"+-----------------------------------------------------------------------------+-- | Returns the time zone offset in minutes.+--+getTimezoneOffset :: Date -> IO Int+getTimezoneOffset date = call0 date "getTimezoneOffset"+-----------------------------------------------------------------------------+-- | Returns the UTC day of the month.+--+getUTCDate :: Date -> IO Int+getUTCDate date = call0 date "getUTCDate"+-----------------------------------------------------------------------------+-- | Returns the UTC day of the week.+--+getUTCDay :: Date -> IO Int+getUTCDay date = call0 date "getUTCDay"+-----------------------------------------------------------------------------+-- | Returns the UTC full year.+--+getUTCFullYear :: Date -> IO Int+getUTCFullYear date = call0 date "getUTCFullYear"+-----------------------------------------------------------------------------+-- | Returns the UTC hour.+--+getUTCHours :: Date -> IO Int+getUTCHours date = call0 date "getUTCHours"+-----------------------------------------------------------------------------+-- | Returns the UTC milliseconds.+--+getUTCMilliseconds :: Date -> IO Int+getUTCMilliseconds date = call0 date "getUTCMilliseconds"+-----------------------------------------------------------------------------+-- | Returns the UTC minutes.+--+getUTCMinutes :: Date -> IO Int+getUTCMinutes date = call0 date "getUTCMinutes"+-----------------------------------------------------------------------------+-- | Returns the UTC month (0-11).+--+getUTCMonth :: Date -> IO Int+getUTCMonth date = call0 date "getUTCMonth"+-----------------------------------------------------------------------------+-- | Returns the UTC seconds.+--+getUTCSeconds :: Date -> IO Int+getUTCSeconds date = call0 date "getUTCSeconds"+-----------------------------------------------------------------------------+-- | Sets the day of the month.+--+setDate :: Int -> Date -> IO Double+setDate day (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setDate" [day]+-----------------------------------------------------------------------------+-- | Sets the full year, with optional month and day.+--+setFullYear :: Int -> Maybe Int -> Maybe Int -> Date -> IO Double+setFullYear year month day (Date d) = do+ y <- DSL.toJSVal year+ m <- traverse DSL.toJSVal month+ d' <- traverse DSL.toJSVal day+ callArgs (Date d) "setFullYear" (catMaybes [Just y, m, d'])+-----------------------------------------------------------------------------+-- | Sets the hour, with optional minutes, seconds, and milliseconds.+--+setHours :: Int -> Maybe Int -> Maybe Int -> Maybe Int -> Date -> IO Double+setHours hours minutes seconds millis (Date d) = do+ h <- DSL.toJSVal hours+ m <- traverse DSL.toJSVal minutes+ s <- traverse DSL.toJSVal seconds+ ms <- traverse DSL.toJSVal millis+ callArgs (Date d) "setHours" (catMaybes [Just h, m, s, ms])+-----------------------------------------------------------------------------+-- | Sets the milliseconds.+--+setMilliseconds :: Int -> Date -> IO Double+setMilliseconds ms (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setMilliseconds" [ms]+-----------------------------------------------------------------------------+-- | Sets the minutes, with optional seconds and milliseconds.+--+setMinutes :: Int -> Maybe Int -> Maybe Int -> Date -> IO Double+setMinutes minutes seconds millis (Date d) = do+ m <- DSL.toJSVal minutes+ s <- traverse DSL.toJSVal seconds+ ms <- traverse DSL.toJSVal millis+ callArgs (Date d) "setMinutes" (catMaybes [Just m, s, ms])+-----------------------------------------------------------------------------+-- | Sets the month, with optional day of the month.+--+setMonth :: Int -> Maybe Int -> Date -> IO Double+setMonth month day (Date d) = do+ m <- DSL.toJSVal month+ d' <- traverse DSL.toJSVal day+ callArgs (Date d) "setMonth" (catMaybes [Just m, d'])+-----------------------------------------------------------------------------+-- | Sets the seconds, with optional milliseconds.+--+setSeconds :: Int -> Maybe Int -> Date -> IO Double+setSeconds seconds millis (Date d) = do+ s <- DSL.toJSVal seconds+ ms <- traverse DSL.toJSVal millis+ callArgs (Date d) "setSeconds" (catMaybes [Just s, ms])+-----------------------------------------------------------------------------+-- | Sets the time in milliseconds since epoch.+--+setTime :: Double -> Date -> IO Double+setTime time (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setTime" [time]+-----------------------------------------------------------------------------+-- | Sets the UTC day of the month.+--+setUTCDate :: Int -> Date -> IO Double+setUTCDate day (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setUTCDate" [day]+-----------------------------------------------------------------------------+-- | Sets the UTC full year, with optional month and day.+--+setUTCFullYear :: Int -> Maybe Int -> Maybe Int -> Date -> IO Double+setUTCFullYear year month day (Date d) = do+ y <- DSL.toJSVal year+ m <- traverse DSL.toJSVal month+ d' <- traverse DSL.toJSVal day+ callArgs (Date d) "setUTCFullYear" (catMaybes [Just y, m, d'])+-----------------------------------------------------------------------------+-- | Sets the UTC hour, with optional minutes, seconds, and milliseconds.+--+setUTCHours :: Int -> Maybe Int -> Maybe Int -> Maybe Int -> Date -> IO Double+setUTCHours hours minutes seconds millis (Date d) = do+ h <- DSL.toJSVal hours+ m <- traverse DSL.toJSVal minutes+ s <- traverse DSL.toJSVal seconds+ ms <- traverse DSL.toJSVal millis+ callArgs (Date d) "setUTCHours" (catMaybes [Just h, m, s, ms])+-----------------------------------------------------------------------------+-- | Sets the UTC milliseconds.+--+setUTCMilliseconds :: Int -> Date -> IO Double+setUTCMilliseconds ms (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setUTCMilliseconds" [ms]+-----------------------------------------------------------------------------+-- | Sets the UTC minutes, with optional seconds and milliseconds.+--+setUTCMinutes :: Int -> Maybe Int -> Maybe Int -> Date -> IO Double+setUTCMinutes minutes seconds millis (Date d) = do+ m <- DSL.toJSVal minutes+ s <- traverse DSL.toJSVal seconds+ ms <- traverse DSL.toJSVal millis+ callArgs (Date d) "setUTCMinutes" (catMaybes [Just m, s, ms])+-----------------------------------------------------------------------------+-- | Sets the UTC month, with optional day of the month.+--+setUTCMonth :: Int -> Maybe Int -> Date -> IO Double+setUTCMonth month day (Date d) = do+ m <- DSL.toJSVal month+ d' <- traverse DSL.toJSVal day+ callArgs (Date d) "setUTCMonth" (catMaybes [Just m, d'])+-----------------------------------------------------------------------------+-- | Sets the UTC seconds, with optional milliseconds.+--+setUTCSeconds :: Int -> Maybe Int -> Date -> IO Double+setUTCSeconds seconds millis (Date d) = do+ s <- DSL.toJSVal seconds+ ms <- traverse DSL.toJSVal millis+ callArgs (Date d) "setUTCSeconds" (catMaybes [Just s, ms])+-----------------------------------------------------------------------------
src/Miso/Delegate.hs view
@@ -1,32 +1,58 @@ -----------------------------------------------------------------------------+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}+----------------------------------------------------------------------------- -- | -- Module : Miso.Delegate--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable+--+-- Types and functions related to [event delegation](https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Event_bubbling#event_delegation)+-- -----------------------------------------------------------------------------module Miso.Delegate where--import Control.Monad.IO.Class-import Data.IORef-import qualified Data.Map as M-import GHCJS.Marshal-import GHCJS.Types (JSVal)-import qualified JavaScript.Object.Internal as OI-import Miso.FFI-import Miso.Html.Types-import Miso.String-+module Miso.Delegate+ ( delegator+ ) where+-----------------------------------------------------------------------------+import Control.Monad.IO.Class (liftIO)+import Data.IORef (IORef, readIORef)+import qualified Data.Map.Strict as M+-----------------------------------------------------------------------------+import Miso.DSL (create, JSVal, Object(..), ToJSVal(toJSVal))+import Miso.Types (VTree(..), Events, Phase)+import Miso.String (MisoString)+import qualified Miso.FFI.Internal as FFI+-----------------------------------------------------------------------------+-- | Local Event type, used to create field names for a delegated event+data Event+ = Event+ { name :: MisoString+ -- ^ Event name+ , capture :: Phase+ -- ^ Capture settings for event+ } deriving (Show, Eq)+-----------------------------------------------------------------------------+-- | Instance used to initialize event delegation+instance ToJSVal Event where+ toJSVal Event {..} = do+ o <- create+ flip (FFI.set "name") o =<< toJSVal name+ flip (FFI.set "capture") o =<< toJSVal capture+ toJSVal o+----------------------------------------------------------------------------- -- | Entry point for event delegation delegator :: JSVal -> IORef VTree- -> M.Map MisoString Bool- -> JSM ()-delegator mountPointElement vtreeRef es = do- evts <- toJSVal (M.toList es)- delegateEvent mountPointElement evts $ do- VTree (OI.Object val) <- liftIO (readIORef vtreeRef)- pure val+ -> Events+ -> Bool+ -> IO ()+delegator mountPointElement vtreeRef es debug = do+ evts <- toJSVal (uncurry Event <$> M.toList es)+ FFI.delegator mountPointElement evts debug $ do+ VTree (Object vtree) <- liftIO (readIORef vtreeRef)+ pure vtree+-----------------------------------------------------------------------------
− src/Miso/Dev.hs
@@ -1,14 +0,0 @@--------------------------------------------------------------------------------- |--- Module : Miso.Dev--- Copyright : (C) 2016-2025 David M. Johnson--- License : BSD3-style (see the file LICENSE)--- Maintainer : David M. Johnson <code@dmj.io>--- Stability : experimental--- Portability : non-portable------------------------------------------------------------------------------module Miso.Dev- ( clearBody- ) where--import Miso.FFI (clearBody)
src/Miso/Diff.hs view
@@ -1,50 +1,45 @@ -----------------------------------------------------------------------------+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+----------------------------------------------------------------------------- -- | -- Module : Miso.Diff--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable+--+-- Functions and helpers for Virtual DOM diffing.+-- -----------------------------------------------------------------------------module Miso.Diff ( diff- , mountElement- ) where--import GHCJS.Foreign.Internal hiding (Object)-import GHCJS.Types-import JavaScript.Object.Internal-import Miso.Html.Types-import Miso.FFI-import Miso.String---- | Entry point for diffing / patching algorithm-diff :: Maybe MisoString -> Maybe VTree -> Maybe VTree -> JSM ()-diff mayElem current new =- case mayElem of- Nothing -> do- body <- getBody- diffElement body current new- Just elemId -> do- e <- getElementById elemId- diffElement e current new-+module Miso.Diff+ ( diff+ , mountElement+ ) where+-----------------------------------------------------------------------------+import qualified Miso.FFI.Internal as FFI+import Miso.Types+import Miso.DSL+----------------------------------------------------------------------------- -- | diffing / patching a given element-diffElement :: JSVal -> Maybe VTree -> Maybe VTree -> JSM ()-diffElement mountEl current new = do- doc <- getDoc- case (current, new) of+diff :: Maybe VTree -> Maybe VTree -> JSVal -> IO ()+diff current new_ mountEl =+ case (current, new_) of (Nothing, Nothing) -> pure () (Just (VTree current'), Just (VTree new')) -> do- diff' current' new' mountEl doc+ FFI.diff current' new' mountEl+ FFI.flush (Nothing, Just (VTree new')) -> do- diff' (Object jsNull) new' mountEl doc+ FFI.diff (Object jsNull) new' mountEl+ FFI.flush (Just (VTree current'), Nothing) -> do- diff' current' (Object jsNull) mountEl doc-+ FFI.diff current' (Object jsNull) mountEl+ FFI.flush+----------------------------------------------------------------------------- -- | return the configured mountPoint element or the body-mountElement :: Maybe MisoString -> JSM JSVal-mountElement mayMp =- case mayMp of- Nothing -> getBody- Just eid -> getElementById eid+mountElement :: MisoString -> IO JSVal+mountElement = \case+ "body" -> FFI.getBody+ e -> FFI.getElementById e+-----------------------------------------------------------------------------
src/Miso/Effect.hs view
@@ -1,97 +1,384 @@ -----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-}+-----------------------------------------------------------------------------+{-# OPTIONS_GHC -fno-warn-orphans #-}+----------------------------------------------------------------------------- -- | -- Module : Miso.Effect--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable ----- This module defines `Effect` and `Sub` types, which are used to define--- `Miso.Types.update` function and `Miso.Types.subs` field of the `Miso.Types.App`.+-- This module defines t'Effect', t'Sub' and t'Sink' types, which are used with the+-- 'Miso.Types.update' function and 'Miso.Types.subs' field of the t'Miso.Types.Component'.+-- -----------------------------------------------------------------------------module Miso.Effect (- module Miso.Effect.Storage-, module Miso.Effect.DOM-, Effect (..), Sub, Sink-, mapSub-, noEff-, (<#)-, (#>)-, batchEff-, effectSub-) where--import Data.Bifunctor--import Control.Monad.IO.Class-import Miso.FFI (JSM)--import Miso.Effect.Storage-import Miso.Effect.DOM---- | An effect represents the results of an update action.+module Miso.Effect+ ( -- ** Effect+ -- *** Types+ Effect+ , Sub+ , Sink+ , DOMRef+ , ComponentInfo (..)+ , ComponentId+ , mkComponentInfo+ -- ** 'IO'+ , Schedule (..)+ , Synchronicity (..)+ -- *** Combinators+ , (<#)+ , (#>)+ , batch+ , batch_+ , io+ , io_+ , sync+ , sync_+ , for+ , issue+ , withSink+ , mapSub+ , noop+ , beforeAll+ , afterAll+ , modifyAllIO+ -- *** Lens+ , componentInfoDOMRef+ , componentInfoParentId+ , componentInfoId+ -- *** Internal+ , runEffect+ ) where+-----------------------------------------------------------------------------+import Control.Monad (void)+import Data.Foldable (for_)+import Control.Monad.RWS (RWS, put, tell, execRWS, censor)+-----------------------------------------------------------------------------+import Miso.Lens+import Miso.DSL.FFI+-----------------------------------------------------------------------------+-- | Smart constructor for t'ComponentInfo'+mkComponentInfo+ :: ComponentId+ -- ^ 'ComponentId'+ -> ComponentId+ -- ^ @parent@ 'ComponentId'+ -> DOMRef+ -- ^ 'DOMRef'+ -> ComponentInfo parent+mkComponentInfo = ComponentInfo+-----------------------------------------------------------------------------+-- | This is the 'Reader r' in t'Miso.Effect'. Accessible via 'Control.Monad.Reader.ask'. It holds+-- a phantom type for @parent@. This is used as a witness when calling the+-- 'parent' function. It gives access to 'Component' metadata such as the 'DOMRef' the+-- 'Component' was mounted on and the 'ComponentId' associated with it.+data ComponentInfo parent+ = ComponentInfo+ { _componentInfoId :: ComponentId+ , _componentInfoParentId :: ComponentId+ , _componentInfoDOMRef :: DOMRef+ }+-----------------------------------------------------------------------------+-- | Lens for accessing the t'ComponentId' from t'ComponentInfo'. ----- It consists of the updated model and a list of subscriptions. Each 'Sub' is--- run in a new thread so there is no risk of accidentally blocking the--- application.-data Effect action model = Effect model [Sub action]---- | Type synonym for constructing event subscriptions.+-- @+-- update = \case+-- SomeAction -> do+-- compId <- view componentInfoId+-- someAction compId+-- @ ----- The 'Sink' callback is used to dispatch actions which are then fed--- back to the 'Miso.Types.update' function.-type Sub action = Sink action -> JSM ()---- | Function to asynchronously dispatch actions to the 'Miso.Types.update' function.+-- @since 1.9.0.0+componentInfoId :: Lens (ComponentInfo parent) ComponentId+componentInfoId = lens _componentInfoId $ \r x -> r { _componentInfoId = x }+-----------------------------------------------------------------------------+-- | Lens for accessing the parents's t'ComponentId' from t'ComponentInfo'.+--+-- @+--+-- update = \case+-- SomeAction -> do+-- compParentId <- view componentParentId+-- someAction compParentId+-- @+--+-- @since 1.9.0.0+componentInfoParentId :: Lens (ComponentInfo parent) ComponentId+componentInfoParentId = lens _componentInfoParentId $ \r x -> r { _componentInfoParentId = x }+-----------------------------------------------------------------------------+-- | Lens for accessing the underlying t'Miso.Types.Component' t'DOMRef'.+--+-- @+-- update = \case+-- SomeAction -> do+-- domRef <- view componentDOMRef+-- someAction domRef+-- @+--+-- @since 1.9.0.0+componentInfoDOMRef :: Lens (ComponentInfo parent) DOMRef+componentInfoDOMRef = lens _componentInfoDOMRef $ \r x -> r { _componentInfoDOMRef = x }+-----------------------------------------------------------------------------+-- | 'ComponentId' of the current t'Miso.Types.Component'+type ComponentId = Int+-----------------------------------------------------------------------------+-- | Type synonym for constructing subscriptions.+--+-- For example usage see "Miso.Subscription"+--+-- The 'Sink' function is used to write to the global event queue.+type Sub action = Sink action -> IO ()+-----------------------------------------------------------------------------+-- | Function to write to the global event queue for processing by the scheduler. type Sink action = action -> IO ()---- | Turn a subscription that consumes actions of type @a@ into a subscription--- that consumes actions of type @b@ using the supplied function of type @a -> b@.-mapSub :: (actionA -> actionB) -> Sub actionA -> Sub actionB-mapSub f sub = \sinkB -> let sinkA = sinkB . f- in sub sinkA--instance Functor (Effect action) where- fmap f (Effect m acts) = Effect (f m) acts--instance Applicative (Effect action) where- pure m = Effect m []- Effect fModel fActs <*> Effect xModel xActs = Effect (fModel xModel) (fActs ++ xActs)--instance Monad (Effect action) where- return = pure- Effect m acts >>= f =- case f m of- Effect m' acts' -> Effect m' (acts ++ acts')--instance Bifunctor Effect where- bimap f g (Effect m acts) = Effect (g m) (map (\act -> \sink -> act (sink . f)) acts)---- | Smart constructor for an 'Effect' with no actions.-noEff :: model -> Effect action model-noEff m = Effect m []-+----------------------------------------------------------------------------- -- | Smart constructor for an 'Effect' with exactly one action.-(<#) :: model -> JSM action -> Effect action model-(<#) m a = effectSub m $ \sink -> a >>= liftIO . sink-+infixl 0 <#+(<#) :: model -> IO action -> Effect parent model action+(<#) m action = put m >> tell [ async $ \f -> f =<< action ]+-----------------------------------------------------------------------------+async :: (Sink action -> IO ()) -> Schedule action+async = Schedule Async+----------------------------------------------------------------------------- -- | `Effect` smart constructor, flipped-(#>) :: JSM action -> model -> Effect action model+infixr 0 #>+(#>) :: IO action -> model -> Effect parent model action (#>) = flip (<#)---- | Smart constructor for an 'Effect' with multiple actions.-batchEff :: model -> [JSM action] -> Effect action model-batchEff model actions = Effect model $- map (\a sink -> liftIO . sink =<< a) actions---- | Like '<#' but schedules a subscription which is an IO computation which has--- access to a 'Sink' which can be used to asynchronously dispatch actions to--- the 'Miso.Types.update' function.+-----------------------------------------------------------------------------+-- | Smart constructor for an 'Effect' with multiple 'IO' actions. ----- A use-case is scheduling an IO computation which creates a 3rd-party JS+-- @since 1.9.0.0+batch+ :: [IO action]+ -- ^ Batch of 'IO' actions to execute+ -> Effect parent model action+batch actions = sequence_+ [ tell [ async $ \f -> f =<< action ]+ | action <- actions+ ]+-----------------------------------------------------------------------------+-- | Like @batch@ but actions are discarded+--+-- @since 1.9.0.0+batch_ :: [IO ()] -> Effect parent model action+batch_ actions = sequence_+ [ tell [ async (const action) ]+ | action <- actions+ ]+-----------------------------------------------------------------------------+-- | A monad for succinctly expressing model transitions in the @update@ function.+--+-- t'Effect' is a @RWS@, where the @State@ allows modification to 'model'.+-- It's also a @Writer@ @Monad@, where the accumulator is a list of scheduled+-- @IO@ actions. Multiple actions can be scheduled using 'Control.Monad.Writer.Class.tell'+-- from the @mtl@ library and a single asynchronous action can be scheduled using 'io_'.+--+-- An t'Effect' represents the results of an 'update' action.+--+-- It consists of the updated model and a list of subscriptions. Each t'Sub' is+-- run in a new thread so there is no risk of accidentally blocking the+-- application.+--+-- Tip: use the t'Effect' monad in combination with the stateful "Miso.Lens"+-- operators (all operators ending in "@=@"). The following example assumes+-- the lenses @field1@, @counter@ and @field2@ are in scope and that the+-- @LambdaCase@ language extension is enabled:+--+-- @+-- myComponent = Component+-- { update = \\case+-- MyAction1 -> do+-- field1 '.=' value1+-- counter '+=' 1+-- MyAction2 -> do+-- field2 '%=' f+-- 'io_' $ do+-- 'consoleLog' \"Hello\"+-- 'consoleLog' \"World!\"+-- , ...+-- }+-- @+type Effect parent model action = RWS (ComponentInfo parent) [Schedule action] model ()+-----------------------------------------------------------------------------+-- | Represents a scheduled 'Effect' that is executed either synchronously+-- or asynchronously.+--+-- All t'IO' is by default asynchronous, use the 'sync' function for synchronous+-- execution. Beware 'sync' can block the render thread for a specific+-- t'Miso.Types.Component'.+--+-- N.B. During t'Miso.Types.Component' unmounting, all effects are evaluated+-- synchronously.+--+-- @since 1.9.0.0+data Schedule action = Schedule Synchronicity (Sink action -> IO ())+-----------------------------------------------------------------------------+-- | Type to represent a DOM reference+type DOMRef = JSVal+-----------------------------------------------------------------------------+-- | Internal function used to unwrap an @Effect@+runEffect+ :: Effect parent model action+ -> ComponentInfo parent+ -> model+ -> (model, [Schedule action])+runEffect = execRWS+-----------------------------------------------------------------------------+-- | Turn a 'Sub' that consumes actions of type @a@ into a 'Sub' that consumes+-- actions of type @b@ using the supplied function of type @a -> b@.+mapSub :: (a -> b) -> Sub a -> Sub b+mapSub f sub = \g -> sub (g . f)+-----------------------------------------------------------------------------+-- | Schedule a single 'IO' action, executed synchronously. For asynchronous+-- execution, see 'io'.+--+-- Please use this with caution because it will block the render thread.+--+-- @since 1.9.0.0+sync+ :: IO action+ -- ^ 'IO' action to execute synchronously+ -> Effect parent model action+sync action = tell [ Schedule Sync $ \f -> f =<< action ]+-----------------------------------------------------------------------------+-- | Like 'sync', except discards the result.+--+-- @since 1.9.0.0+sync_+ :: IO ()+ -- ^ 'IO' action to execute synchronously+ -> Effect parent model action+sync_ action = tell [ Schedule Sync $ \_ -> action ]+-----------------------------------------------------------------------------+-- | Schedule a single 'IO' action for later execution.+--+-- Note that multiple 'IO' action can be scheduled using+-- 'Control.Monad.Writer.Class.tell' from the @mtl@ library.+--+-- @since 1.9.0.0+io+ :: IO action+ -- ^ 'IO' action to execute asynchronously+ -> Effect parent model action+io action = withSink (action >>=)+-----------------------------------------------------------------------------+-- | Like 'io' but doesn't cause an action to be dispatched to+-- the @update@ function.+--+-- This is handy for scheduling @IO@ computations where you don't care+-- about their results or when they complete.+--+-- Note: The result of @IO a@ is discarded.+--+-- @since 1.9.0.0+io_+ :: IO ()+ -- ^ 'IO' action to execute asynchronously+ -> Effect parent model action+io_ action = withSink (\_ -> void action)+-----------------------------------------------------------------------------+-- | Like 'io' but generalized to any instance of 'Foldable'+--+-- This is handy for scheduling @IO@ computations that return a @Maybe@ value+--+-- @since 1.9.0.0+for+ :: Foldable f+ => IO (f action)+ -- ^ @actions@ executed in batch.+ -> Effect parent model action+for actions = withSink $ \sink -> actions >>= flip for_ sink+-----------------------------------------------------------------------------+-- | Performs the given 'IO' action before all IO actions collected by the given+-- effect.+--+-- @+-- -- delays connecting a websocket by 100000 microseconds+-- beforeAll (liftIO $ threadDelay 100000) $ websocketConnectJSON OnConnect OnClose OnOpen OnError+-- @+--+-- @since 1.9.0.0+beforeAll :: IO () -> Effect parent model action -> Effect parent model action+beforeAll = modifyAllIO . (*>)+-----------------------------------------------------------------------------+-- | Performs the given 'IO' action after all IO actions collected by the given+-- effect.+--+-- Example usage:+--+-- > -- log that running the a websocket Effect completed+-- > afterAll (consoleLog "Done running websocket effect") $ websocketConnectJSON OnConnect OnClose OnOpen OnError+afterAll :: IO () -> Effect parent model action -> Effect parent model action+afterAll = modifyAllIO . (<*)+-----------------------------------------------------------------------------+-- | Modifies all 'IO' collected by the given Effect.+--+-- All 'IO' expressions collected by 'Effect' can be evaluated either+-- synchronously or asynchronously (the default).+--+-- This function can be used to adjoin additional actions to all 'IO'+-- expressions in an 'Effect'. For examples see 'beforeAll' and 'afterAll'.+modifyAllIO+ :: (IO () -> IO ())+ -> Effect parent model action+ -> Effect parent model action+modifyAllIO f = censor $ \actions ->+ [ Schedule x (f <$> action)+ | Schedule x action <- actions+ ]+-----------------------------------------------------------------------------+-- | @withSink@ allows users to write to the global event queue. This is useful for introducing 'IO' into the system.+-- A synonym for 'Control.Monad.Writer.tell', specialized to 'Effect'.+--+-- A use-case is scheduling an 'IO' computation which creates a 3rd-party JS -- widget which has an associated callback. The callback can then call the sink--- to turn events into actions. To do this without accessing a sink requires--- going via a @'Sub'scription@ which introduces a leaky-abstraction.-effectSub :: model -> Sub action -> Effect action model-effectSub model sub = Effect model [sub]+-- to turn events into actions.+--+-- @+-- 'update' FetchJSON = 'withSink' $ \sink -> getJSON (sink . ReceivedJSON) (sink . HandleError)+-- @+--+-- @since 1.9.0.0+withSink+ :: (Sink action -> IO ())+ -- ^ Callback function that provides access to the underlying 'Sink'.+ -> Effect parent model action+withSink f = tell [ async f ]+-----------------------------------------------------------------------------+-- | Issue a new @action@ to be processed by 'Miso.Types.update'.+--+-- @+-- data Action = HelloWorld+-- type Model = Int+--+-- 'update' :: Action -> 'Effect' parent Model Action+-- 'update' = \\case+-- Click -> 'issue' HelloWorld+-- @+--+-- @since 1.9.0.0+issue+ :: action+ -- ^ @action@ to raise+ -> Effect parent model action+issue action = tell [ async $ \f -> f action ]+-----------------------------------------------------------------------------+-- | Helper for t'Miso.Types.Component' construction, when you want to ignore the 'Miso.Types.update'+-- function temporarily, or permanently.+--+-- @since 1.9.0.0+noop :: action -> Effect parent model action+noop = const (pure ())+-----------------------------------------------------------------------------+-- | Type to indicate if effects should be handled asynchronously+-- or synchronously.+--+data Synchronicity+ = Async+ | Sync+ deriving (Show, Eq)+-----------------------------------------------------------------------------
− src/Miso/Effect/DOM.hs
@@ -1,17 +0,0 @@--------------------------------------------------------------------------------- |--- Module : Miso.Effect.DOM--- Copyright : (C) 2016-2025 David M. Johnson--- License : BSD3-style (see the file LICENSE)--- Maintainer : David M. Johnson <code@dmj.io>--- Stability : experimental--- Portability : non-portable------------------------------------------------------------------------------module Miso.Effect.DOM- ( focus- , blur- , scrollIntoView- , alert- ) where--import Miso.FFI
− src/Miso/Effect/Storage.hs
@@ -1,125 +0,0 @@-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE LambdaCase #-}--------------------------------------------------------------------------------- |--- Module : Miso.Effect.Storage--- Copyright : (C) 2016-2025 David M. Johnson--- License : BSD3-style (see the file LICENSE)--- Maintainer : David M. Johnson <code@dmj.io>--- Stability : experimental--- Portability : non-portable------ This module provides an interface to the--- [Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API).------------------------------------------------------------------------------module Miso.Effect.Storage- ( -- * Retrieve storage- getLocalStorage- , getSessionStorage- -- * Set items in storage- , setLocalStorage- , setSessionStorage- -- * Remove items from storage- , removeLocalStorage- , removeSessionStorage- -- * Clear storage- , clearLocalStorage- , clearSessionStorage- -- * Get number of items in storage- , localStorageLength- , sessionStorageLength- ) where--import Data.Aeson hiding (Object, String)-import GHCJS.Marshal-import GHCJS.Types--import Miso.FFI-import qualified Miso.FFI.Storage as Storage-import Miso.String---- | Helper for retrieving either local or session storage-getStorageCommon- :: FromJSON b => (t -> JSM (Maybe JSVal)) -> t -> JSM (Either String b)-getStorageCommon f key = do- result :: Maybe JSVal <- f key- case result of- Nothing -> pure $ Left "Not Found"- Just v -> do- r <- parse v- pure $ case fromJSON r of- Success x -> Right x- Error y -> Left y---- | Retrieve a value stored under given key in session storage-getSessionStorage :: FromJSON model => MisoString -> JSM (Either String model)-getSessionStorage =- getStorageCommon $ \t -> do- s <- Storage.sessionStorage- r <- Storage.getItem s t- fromJSVal r---- | Retrieve a value stored under given key in local storage-getLocalStorage :: FromJSON model => MisoString -> JSM (Either String model)-getLocalStorage = getStorageCommon $ \t -> do- s <- Storage.localStorage- r <- Storage.getItem s t- fromJSVal r---- | Set the value of a key in local storage.------ @setLocalStorage key value@ sets the value of @key@ to @value@.-setLocalStorage :: ToJSON model => MisoString -> model -> JSM ()-setLocalStorage key model = do- s <- Storage.localStorage- Storage.setItem s key =<< stringify model---- | Set the value of a key in session storage.------ @setSessionStorage key value@ sets the value of @key@ to @value@.-setSessionStorage :: ToJSON model => MisoString -> model -> JSM ()-setSessionStorage key model = do- s <- Storage.sessionStorage- Storage.setItem s key =<< stringify model---- | Removes an item from local storage------ @removeLocalStorage key@ removes the value of @key@.-removeLocalStorage :: MisoString -> JSM ()-removeLocalStorage key = do- s <- Storage.localStorage- Storage.removeItem s key---- | Removes an item from session storage.------ @removeSessionStorage key@ removes the value of @key@.-removeSessionStorage :: MisoString -> JSM ()-removeSessionStorage key = do- s <- Storage.sessionStorage- Storage.removeItem s key---- | Clear local storage------ @clearLocalStorage@ removes all values from local storage.-clearLocalStorage :: JSM ()-clearLocalStorage = Storage.clear =<< Storage.localStorage---- | Clear session storage------ @clearSessionStorage@ removes all values from session storage.-clearSessionStorage :: JSM ()-clearSessionStorage = Storage.clear =<< Storage.sessionStorage---- | Local storage length------ @localStorageLength@ returns the count of items in local storage-localStorageLength :: JSM Int-localStorageLength = Storage.length =<< Storage.localStorage---- | Session storage length------ @sessionStorageLength@ returns the count of items in session storage-sessionStorageLength :: JSM Int-sessionStorageLength = Storage.length =<< Storage.sessionStorage
src/Miso/Event.hs view
@@ -1,17 +1,184 @@ -----------------------------------------------------------------------------+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+----------------------------------------------------------------------------- -- | -- Module : Miso.Event--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable+--+-- Functions for specifying component lifecycle events and event handlers in 'Miso.Types.View'.+-- ---------------------------------------------------------------------------- module Miso.Event- ( module Miso.Event.Decoder+ ( -- *** Smart constructors+ on+ , onCapture+ , onWithOptions+ , Phase (..)+ -- *** Lifecycle events+ , onCreated+ , onCreatedWith+ , onBeforeCreated+ , onDestroyed+ , onBeforeDestroyed+ , onBeforeDestroyedWith+ -- *** Exports+ , module Miso.Event.Decoder , module Miso.Event.Types ) where--import Miso.Event.Decoder-import Miso.Event.Types-+-----------------------------------------------------------------------------+import Control.Monad (when)+import qualified Data.Map.Strict as M+import Miso.JSON (parseEither)+-----------------------------------------------------------------------------+import Miso.DSL+import Miso.Event.Decoder+import Miso.Event.Types+import qualified Miso.FFI.Internal as FFI+import Miso.Types (Attribute (On), LogLevel(..), DOMRef, VTree(..))+import Miso.String (MisoString, ms)+-----------------------------------------------------------------------------+-- | Convenience wrapper for @onWithOptions defaultOptions@.+--+-- > let clickHandler = on "click" emptyDecoder $ \() -> Action+-- > in button_ [ clickHandler, class_ "add" ] [ text_ "+" ]+--+-- This is used to define events that are triggered during the browser+-- bubble phase.+--+on :: MisoString+ -> Decoder r+ -> (r -> DOMRef -> action)+ -> Attribute action+on = onWithOptions BUBBLE defaultOptions+-----------------------------------------------------------------------------+-- | Convenience wrapper for @onWithOptions (True :: Capture)@.+--+-- > let clickHandler = onCapture "click" emptyDecoder $ \() -> Action+-- > in button_ [ clickHandler, class_ "add" ] [ text_ "+" ]+--+-- This is used to define events that are triggered during the browser+-- capture phase.+--+onCapture + :: MisoString+ -> Decoder r+ -> (r -> DOMRef -> action)+ -> Attribute action+onCapture = onWithOptions CAPTURE defaultOptions+-----------------------------------------------------------------------------+-- | @onWithOptions opts eventName decoder toAction@ is an attribute+-- that will set the event handler of the associated DOM node to a function that+-- decodes its argument using @decoder@, converts it to an action+-- using @toAction@ and then feeds that action back to the @update@ function.+--+-- @opts@ can be used to disable further event propagation.+--+-- > let clickHandler = onWithOptions defaultOptions "click" emptyDecoder $ \() -> Action+-- > in button_ [ clickHandler, class_ "add" ] [ text_ "+" ]+--+onWithOptions+ :: Phase+ -> Options+ -> MisoString+ -> Decoder r+ -> (r -> DOMRef -> action)+ -> Attribute action+onWithOptions phase options eventName Decoder{..} toAction =+ On $ \sink (VTree n) logLevel events -> do+ when (logLevel == DebugAll || logLevel == DebugEvents) $+ case M.lookup eventName events of+ Nothing ->+ FFI.consoleError $ mconcat+ [ "Event \""+ , eventName+ , "\" is not being listened on. To use this event, "+ , "add to the 'events' Map in Component"+ ]+ _ -> pure ()+ eventsVal <-+ getProp "events" n+ eventObj <-+ case phase of+ CAPTURE -> getProp "captures" (Object eventsVal)+ BUBBLE -> getProp "bubbles" (Object eventsVal)+ eventHandlerObject@(Object eo) <- create+ jsOptions <- toJSVal options+ decodeAtVal <- toJSVal decodeAt+ cb <- FFI.asyncCallback2 $ \e domRef -> do+ Just v <- fromJSVal =<< FFI.eventJSON decodeAtVal e+ case parseEither decoder v of+ Left msg -> FFI.consoleError ("[EVENT DECODE ERROR]: " <> ms msg)+ Right event -> sink (toAction event domRef)+ FFI.set "runEvent" cb eventHandlerObject+ FFI.set "options" jsOptions eventHandlerObject+ FFI.set eventName eo (Object eventObj)+-----------------------------------------------------------------------------+-- | @onCreated action@ is an event that gets called after the actual DOM+-- element is created.+--+-- @since 1.9.0.0+--+onCreated :: action -> Attribute action+onCreated action =+ On $ \sink (VTree object) _ _ -> do+ callback <- FFI.syncCallback (sink action)+ FFI.set "onCreated" callback object+-----------------------------------------------------------------------------+-- | Like @onCreated action@ but passes along the `DOMRef`+--+-- @since 1.9.0.0+--+onCreatedWith :: (DOMRef -> action) -> Attribute action+onCreatedWith action =+ On $ \sink (VTree object) _ _ -> do+ callback <- FFI.syncCallback1 (sink . action)+ FFI.set "onCreated" callback object+-----------------------------------------------------------------------------+-- | @onDestroyed action@ is an event that gets called after the DOM element+-- is removed from the DOM.+--+-- @since 1.9.0.0+--+onDestroyed :: action -> Attribute action+onDestroyed action =+ On $ \sink (VTree object) _ _ -> do+ callback <- FFI.syncCallback (sink action)+ FFI.set "onDestroyed" callback object+-----------------------------------------------------------------------------+-- | @onBeforeDestroyed action@ is an event that gets called before the DOM element+-- is removed from the DOM.+--+-- @since 1.9.0.0+--+onBeforeDestroyed :: action -> Attribute action+onBeforeDestroyed action =+ On $ \sink (VTree object) _ _ -> do+ callback <- FFI.syncCallback (sink action)+ FFI.set "onBeforeDestroyed" callback object+-----------------------------------------------------------------------------+-- | Like @onBeforeDestroyed@ but passes along the `DOMRef`+--+-- @since 1.9.0.0+--+onBeforeDestroyedWith :: (DOMRef -> action) -> Attribute action+onBeforeDestroyedWith action =+ On $ \sink (VTree object) _ _ -> do+ callback <- FFI.syncCallback1 (sink . action)+ FFI.set "onBeforeDestroyed" callback object+-----------------------------------------------------------------------------+-- | @onBeforeCreated action@ is an event that gets called before the DOM element+-- is created on the DOM.+--+-- @since 1.9.0.0+--+onBeforeCreated :: action -> Attribute action+onBeforeCreated action =+ On $ \sink (VTree object) _ _ -> do+ callback <- FFI.syncCallback (sink action)+ FFI.set "onBeforeCreated" callback object+-----------------------------------------------------------------------------
src/Miso/Event/Decoder.hs view
@@ -1,94 +1,128 @@-{-# LANGUAGE OverloadedStrings #-}+-----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-} ----------------------------------------------------------------------------- -- | -- Module : Miso.Event.Decoder--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable ---------------------------------------------------------------------------- module Miso.Event.Decoder- ( -- * Decoder+ ( -- ** Types Decoder (..) , DecodeTarget (..)+ -- ** Combinators , at- -- * Decoders+ -- ** Decoders , emptyDecoder , keycodeDecoder , keyInfoDecoder , checkedDecoder , valueDecoder- )- where--import Data.Aeson.Types+ , pointerDecoder+ ) where+----------------------------------------------------------------------------- import Control.Applicative-import GHCJS.Marshal (ToJSVal, toJSVal)-+-----------------------------------------------------------------------------+import Miso.DSL (ToJSVal(toJSVal)) import Miso.Event.Types+import Miso.JSON import Miso.String---- | Data type representing path (consisting of field names) within event object, where a decoder should be applied.+-----------------------------------------------------------------------------+-- | Data type representing path (consisting of field names) within event object+-- where a decoder should be applied. data DecodeTarget- = DecodeTarget [MisoString] -- ^ Specify single path within Event object, where a decoder should be applied.- | DecodeTargets [[MisoString]] -- ^ Specify multiple paths withing Event object, where decoding should be attempted. The first path where decoding suceeds is the one taken.---- | `ToJSVal` instance for `Decoder`+ = DecodeTarget [MisoString]+ -- ^ Specify single path within Event object, where a decoder should be applied.+ | DecodeTargets [[MisoString]]+ -- ^ Specify multiple paths withing Event object, where decoding should be attempted. The first path where decoding suceeds is the one taken.+-----------------------------------------------------------------------------+-- | `ToJSVal` instance for t'DecodeTarget'. instance ToJSVal DecodeTarget where- toJSVal (DecodeTarget xs) = toJSVal xs- toJSVal (DecodeTargets xs) = toJSVal xs---- | Decoder data type for parsing events-data Decoder a = Decoder {- decoder :: Value -> Parser a -- ^ FromJSON-based Event decoder-, decodeAt :: DecodeTarget -- ^ Location in DOM of where to decode-}---- | Smart constructor for building a `Decoder`.+ toJSVal = \case+ DecodeTarget xs -> toJSVal xs+ DecodeTargets xs -> toJSVal xs+-----------------------------------------------------------------------------+-- | t'Decoder' data type for parsing events+data Decoder a+ = Decoder+ { decoder :: Value -> Parser a+ -- ^ FromJSON-based Event decoder+ , decodeAt :: DecodeTarget+ -- ^ Location in DOM of where to decode+ }+-----------------------------------------------------------------------------+-- | Smart constructor for building a t'Decoder'. at :: [MisoString] -> (Value -> Parser a) -> Decoder a at decodeAt decoder = Decoder {decodeAt = DecodeTarget decodeAt, ..}---- | Empty decoder for use with events like "click" that do not+-----------------------------------------------------------------------------+-- | Empty t'Decoder' for use with events like "click" that do not -- return any meaningful values emptyDecoder :: Decoder () emptyDecoder = mempty `at` go where go = withObject "emptyDecoder" $ \_ -> pure ()---- | Retrieves either "keyCode", "which" or "charCode" field in `Decoder`+-----------------------------------------------------------------------------+-- | Retrieves either "keyCode", "which" or "charCode" field in t'Decoder' keycodeDecoder :: Decoder KeyCode keycodeDecoder = Decoder {..} where decodeAt = DecodeTarget mempty decoder = withObject "event" $ \o -> KeyCode <$> (o .: "keyCode" <|> o .: "which" <|> o .: "charCode")---- | Retrieves either "keyCode", "which" or "charCode" field in `Decoder`, along with shift, ctrl, meta and alt.+-----------------------------------------------------------------------------+-- | Retrieves either "keyCode", "which" or "charCode" field in t'Decoder',+-- along with shift, ctrl, meta and alt. keyInfoDecoder :: Decoder KeyInfo keyInfoDecoder = Decoder {..} where- decodeAt = DecodeTarget mempty+ decodeAt =+ DecodeTarget mempty decoder = withObject "event" $ \o ->- KeyInfo <$> (o .: "keyCode" <|> o .: "which" <|> o .: "charCode")- <*> o .: "shiftKey"- <*> o .: "metaKey"- <*> o .: "ctrlKey"- <*> o .: "altKey"---- | Retrieves "value" field in `Decoder`+ KeyInfo+ <$> (o .: "keyCode" <|> o .: "which" <|> o .: "charCode")+ <*> o .: "shiftKey"+ <*> o .: "metaKey"+ <*> o .: "ctrlKey"+ <*> o .: "altKey"+-----------------------------------------------------------------------------+-- | Retrieves "value" field in t'Decoder' valueDecoder :: Decoder MisoString valueDecoder = Decoder {..} where decodeAt = DecodeTarget ["target"] decoder = withObject "target" $ \o -> o .: "value"---- | Retrieves "checked" field in Decoder+-----------------------------------------------------------------------------+-- | Retrieves "checked" field in t'Decoder' checkedDecoder :: Decoder Checked checkedDecoder = Decoder {..} where decodeAt = DecodeTarget ["target"] decoder = withObject "target" $ \o ->- Checked <$> (o .: "checked")+ Checked <$> (o .: "checked")+-----------------------------------------------------------------------------+-- | Pointer t'Decoder' for use with events like "onpointerover"+pointerDecoder :: Decoder PointerEvent+pointerDecoder = Decoder {..}+ where+ pair o x y = liftA2 (,) (o .: x) (o .: y)+ decodeAt = DecodeTarget mempty+ decoder = withObject "pointerDecoder" $ \o ->+ PointerEvent+ <$> o .: "pointerType"+ <*> o .: "pointerId"+ <*> o .: "isPrimary"+ <*> pair o "clientX" "clientY"+ <*> pair o "screenX" "screenY"+ <*> pair o "offsetX" "offsetY"+ <*> pair o "pageX" "pageY"+ <*> pair o "tiltX" "tiltY"+ <*> o .: "pressure"+ <*> o .: "button"+-----------------------------------------------------------------------------
src/Miso/Event/Types.hs view
@@ -1,82 +1,267 @@-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE OverloadedStrings #-}+-----------------------------------------------------------------------------+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} ----------------------------------------------------------------------------- -- | -- Module : Miso.Event.Types--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable -----------------------------------------------------------------------------module Miso.Event.Types where--import qualified Data.Map as M-import GHC.Generics-import GHCJS.Marshal (ToJSVal)-import Miso.String-import Data.Aeson (FromJSON)-+module Miso.Event.Types+ ( -- ** Types+ Events+ , Phase (..)+ -- *** KeyboardEvent+ , KeyInfo (..)+ , KeyCode (..)+ -- *** CheckedEvent+ , Checked (..)+ -- *** PointerEvent+ , PointerEvent (..)+ , PointerType (..)+ -- *** Options+ , Options (..)+ , defaultOptions+ , preventDefault+ , stopPropagation+ -- *** Events+ , defaultEvents+ , keyboardEvents+ , mouseEvents+ , dragEvents+ , pointerEvents+ , mediaEvents+ , clipboardEvents+ , touchEvents+ ) where+-----------------------------------------------------------------------------+import Miso.JSON (FromJSON(..), withText)+import qualified Data.Map.Strict as M+-----------------------------------------------------------------------------+import Miso.DSL+import Miso.String (MisoString, ms)+----------------------------------------------------------------------------- -- | Type useful for both KeyCode and additional key press information. data KeyInfo = KeyInfo { keyCode :: !KeyCode , shiftKey, metaKey, ctrlKey, altKey :: !Bool } deriving (Show, Eq)-+----------------------------------------------------------------------------- -- | Type used for Keyboard events. -- -- See <https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode#Browser_compatibility> newtype KeyCode = KeyCode Int- deriving (Show, Eq, Ord, FromJSON)-+ deriving (Show, Eq, Ord, FromJSON, Num)+----------------------------------------------------------------------------- -- | Type used for Checkbox events. newtype Checked = Checked Bool deriving (Show, Eq, Ord, FromJSON)---- | Options for handling event propagation.-data Options = Options {- preventDefault :: Bool- , stopPropagation :: Bool- } deriving (Show, Eq, Generic)--instance ToJSVal Options---- | Default value for 'Options'.+-----------------------------------------------------------------------------+-- | Type used for Pointer events.+-- <https://w3c.github.io/pointerevents>+data PointerEvent+ = PointerEvent+ { pointerType :: PointerType+ , pointerId :: Int+ , isPrimary :: Bool+ , client :: (Double, Double)+ -- ^ clientX, clientY+ , screen :: (Double, Double)+ -- ^ screenX, screenY+ , offset :: (Double, Double)+ -- ^ offsetX, offsetY+ , page :: (Double,Double)+ -- ^ pageX, pageY+ , tilt :: (Double,Double)+ -- ^ tiltX, tiltY+ , pressure :: Double+ , button :: Int+ -- ^ https://w3c.github.io/pointerevents/#the-button-property+ } deriving (Show, Eq)+-----------------------------------------------------------------------------+-- | Pointer type+-- <https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/pointerType>+data PointerType+ = MousePointerType+ | PenPointerType+ | TouchPointerType+ | UnknownPointerType MisoString+ deriving (Show, Eq)+-----------------------------------------------------------------------------+instance FromJSON PointerType where+ parseJSON = withText "PointerType" $ \case+ "mouse" -> pure MousePointerType+ "touch" -> pure TouchPointerType+ "pen" -> pure PenPointerType+ x -> pure (UnknownPointerType (ms x))+-----------------------------------------------------------------------------+-- | t'Options' for handling event propagation.+data Options+ = Options+ { _preventDefault :: Bool+ , _stopPropagation :: Bool+ } deriving (Show, Eq)+-----------------------------------------------------------------------------+instance Monoid Options where+ mempty = defaultOptions+-----------------------------------------------------------------------------+instance Semigroup Options where+ Options p1 s1 <> Options p2 s2 = Options (p1 || p2) (s1 || s2)+-----------------------------------------------------------------------------+-- | Smart constructor for specifying 'preventDefault' --+-- @since 1.9.0.0+preventDefault :: Options+preventDefault = defaultOptions { _preventDefault = True }+-----------------------------------------------------------------------------+-- | Smart constructor for specifying 'stopPropagation'+--+-- @since 1.9.0.0+stopPropagation :: Options+stopPropagation = defaultOptions { _stopPropagation = True }+-----------------------------------------------------------------------------+instance ToJSVal Options where+ toJSVal Options {..} = do+ o <- create+ flip (setProp "preventDefault") o =<< toJSVal _preventDefault+ flip (setProp "stopPropagation") o =<< toJSVal _stopPropagation+ toJSVal o+-----------------------------------------------------------------------------+-- | Default value for @Options@.+-- -- > defaultOptions = Options { preventDefault = False, stopPropagation = False } defaultOptions :: Options-defaultOptions = Options False False---- | Related to using drop-related events-newtype AllowDrop = AllowDrop Bool- deriving (Show, Eq, FromJSON)-+defaultOptions+ = Options+ { _preventDefault = False+ , _stopPropagation = False+ }+-----------------------------------------------------------------------------+-- | Convenience type for Events+type Events = M.Map MisoString Phase+----------------------------------------------------------------------------- -- | Default delegated events-defaultEvents :: M.Map MisoString Bool-defaultEvents = M.fromList [- ("blur", True)- , ("change", False)- , ("click", False)- , ("dblclick", False)- , ("focus", False)- , ("input", False)- , ("keydown", False)- , ("keypress", False)- , ("keyup", False)- , ("mouseup", False)- , ("mousedown", False)- , ("mouseenter", True)- , ("mouseleave", False)- , ("mouseover", False)- , ("mouseout", False)- , ("dragstart", False)- , ("dragover", False)- , ("dragend", False)- , ("dragenter", False)- , ("dragleave", False)- , ("drag", False)- , ("drop", False)- , ("submit", False)+defaultEvents :: Events+defaultEvents = M.fromList+ [ ("blur", CAPTURE)+ , ("change", BUBBLE)+ , ("click", BUBBLE)+ , ("contextmenu", BUBBLE)+ , ("dblclick", BUBBLE)+ , ("focus", CAPTURE)+ , ("input", BUBBLE)+ , ("select", BUBBLE)+ , ("submit", BUBBLE) ]+-----------------------------------------------------------------------------+-- | Keyboard events+keyboardEvents :: Events+keyboardEvents = M.fromList+ [ ("keydown", BUBBLE)+ , ("keypress", BUBBLE)+ , ("keyup", BUBBLE)+ ]+-----------------------------------------------------------------------------+-- | Mouse events+mouseEvents :: Events+mouseEvents = M.fromList+ [ ("mouseup", BUBBLE)+ , ("mousedown", BUBBLE)+ , ("mouseenter", CAPTURE)+ , ("mouseleave", BUBBLE)+ , ("mouseover", BUBBLE)+ , ("mouseout", BUBBLE)+ , ("contextmenu", BUBBLE)+ ]+-----------------------------------------------------------------------------+-- | Drag events+dragEvents :: Events+dragEvents = M.fromList+ [ ("dragstart", BUBBLE)+ , ("dragover", BUBBLE)+ , ("dragend", BUBBLE)+ , ("dragenter", BUBBLE)+ , ("dragleave", BUBBLE)+ , ("drag", BUBBLE)+ , ("drop", BUBBLE)+ ]+-----------------------------------------------------------------------------+-- | Pointer events+pointerEvents :: Events+pointerEvents = M.fromList+ [ ("pointerup", BUBBLE)+ , ("pointerdown", BUBBLE)+ , ("pointerenter", CAPTURE)+ , ("pointercancel", BUBBLE)+ , ("pointerleave", BUBBLE)+ , ("pointerover", BUBBLE)+ , ("pointerout", BUBBLE)+ , ("contextmenu", BUBBLE)+ ]+-----------------------------------------------------------------------------+-- | Audio video events+-- For use with the @<audio>@ and @<video>@ tags.+--+-- @+-- myApp :: 'Miso.Types.App' Model Action+-- myApp = ('Miso.Types.component' model update view){ events = 'defaultEvents' <> 'mediaEvents' }+-- @+mediaEvents :: Events+mediaEvents = M.fromList+ [ ("abort", CAPTURE)+ , ("canplay", CAPTURE)+ , ("canplaythrough", CAPTURE)+ , ("durationchange", BUBBLE)+ , ("emptied", CAPTURE)+ , ("ended", CAPTURE)+ , ("error", CAPTURE)+ , ("loadeddata", BUBBLE)+ , ("loadedmetadata", BUBBLE)+ , ("loadstart", BUBBLE)+ , ("pause", CAPTURE)+ , ("play", CAPTURE)+ , ("playing", CAPTURE)+ , ("progress", CAPTURE)+ , ("ratechange", CAPTURE)+ , ("seeked", CAPTURE)+ , ("seeking", CAPTURE)+ , ("stalled", CAPTURE)+ , ("suspend", CAPTURE)+ , ("timeupdate", CAPTURE)+ , ("volumechange", CAPTURE)+ , ("waiting", CAPTURE)+ ]+-----------------------------------------------------------------------------+-- | Clipboard events+clipboardEvents :: Events+clipboardEvents = M.fromList+ [ ("cut", BUBBLE)+ , ("copy", BUBBLE)+ , ("paste", BUBBLE)+ ]+-----------------------------------------------------------------------------+-- | Touch events+touchEvents :: Events+touchEvents = M.fromList+ [ ("touchstart", BUBBLE)+ , ("touchcancel", BUBBLE)+ , ("touchmove", BUBBLE)+ , ("touchend", BUBBLE)+ ]+-----------------------------------------------------------------------------+-- | Phase during which event listener is invoked.+--+-- @since 1.9.0.0+data Phase = CAPTURE | BUBBLE deriving (Eq, Show)+-----------------------------------------------------------------------------+instance ToJSVal Phase where+ toJSVal = \case+ CAPTURE -> toJSVal True+ BUBBLE -> toJSVal False+-----------------------------------------------------------------------------
+ src/Miso/EventSource.hs view
@@ -0,0 +1,66 @@+-----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.EventSource+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- Functions and types for working with [Server Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)+--+----------------------------------------------------------------------------+module Miso.EventSource+ ( -- *** EventSource+ connectText+ , connectJSON+ , close+ , socketState+ -- *** Defaults+ , emptyEventSource+ -- *** Types+ , EventSource (..)+ , URL+ -- *** Re-exports+ , Payload (..)+ ) where+-----------------------------------------------------------------------------+import Miso.JSON+-----------------------------------------------------------------------------+import Miso.Effect+import Miso.Runtime+import Miso.String+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/EventSource>+connectText+ :: URL+ -> (EventSource -> action)+ -- ^ onOpen+ -> (MisoString -> action)+ -- ^ onMessage+ -> (MisoString -> action)+ -- ^ onError+ -> Effect parent model action+connectText = eventSourceConnectText+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/EventSource>+connectJSON+ :: FromJSON value+ => URL+ -> (EventSource -> action)+ -- ^ onOpen+ -> (value -> action)+ -- ^ onMessage+ -> (MisoString -> action)+ -- ^ onError+ -> Effect parent model action+connectJSON = eventSourceConnectJSON+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/EventSource/close>+close+ :: EventSource+ -> Effect parent model action+close = eventSourceClose+-----------------------------------------------------------------------------
src/Miso/FFI.hs view
@@ -1,293 +1,115 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE ViewPatterns #-}-{-# LANGUAGE LambdaCase #-} ----------------------------------------------------------------------------- -- | -- Module : Miso.FFI--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable------------------------------------------------------------------------------module Miso.FFI- ( JSM- , forkJSM- , asyncCallback- , asyncCallback1- , callbackToJSVal- , objectToJSVal- , ghcjsPure- , syncPoint- , addEventListener- , windowAddEventListener- , windowInnerHeight- , windowInnerWidth- , eventPreventDefault- , eventStopPropagation- , now- , consoleLog- , consoleLogJSVal- , stringify- , parse- , clearBody- , objectToJSON- , set- , getBody- , getDoc- , getElementById- , diff'- , integralToJSString- , realFloatToJSString- , jsStringToDouble- , delegateEvent- , copyDOMIntoVTree- , swapCallbacks- , releaseCallbacks- , registerCallback- , focus- , blur- , scrollIntoView- , alert- ) where--import Control.Concurrent-import Control.Monad.IO.Class-import Data.Aeson hiding (Object)-import qualified Data.JSString as JSS-import GHCJS.Marshal-import GHCJS.Types-import qualified JavaScript.Object.Internal as OI-#ifdef ghcjs_HOST_OS-import Language.Javascript.JSaddle hiding (obj, val)-#else-import Language.Javascript.JSaddle hiding (Success, obj, val)-#endif-import Miso.String---- | Run given `JSM` action asynchronously, in a separate thread.-forkJSM :: JSM () -> JSM ()-forkJSM a = do- ctx <- askJSM- _ <- liftIO (forkIO (runJSM a ctx))- pure ()---- | Creates an asynchronous callback function-asyncCallback :: JSM () -> JSM Function-asyncCallback a = asyncFunction (\_ _ _ -> a)---- | Creates an asynchronous callback function with a single argument-asyncCallback1 :: (JSVal -> JSM ()) -> JSM Function-asyncCallback1 f = asyncFunction (\_ _ [x] -> f x)---- | Convert a Callback into a JSVal-callbackToJSVal :: Function -> JSM JSVal-callbackToJSVal = toJSVal---- | Convert an Object into a JSVal-objectToJSVal :: Object -> JSM JSVal-objectToJSVal = toJSVal---- | Set property on object-set :: ToJSVal v => MisoString -> v -> OI.Object -> JSM ()-set (unpack -> "class") v obj = do- classSet <- ((JSS.pack "class") `Prelude.elem`) <$> listProps obj- if classSet- then do- classStr <- fromJSValUnchecked =<< getProp (JSS.pack "class") obj- vStr <- fromJSValUnchecked =<< toJSVal v- v' <- toJSVal (classStr <> JSS.pack " " <> vStr)- setProp (JSS.pack "class") v' obj- else do- v' <- toJSVal v- setProp (JSS.pack "class") v' obj-set k v obj = do- v' <- toJSVal v- setProp (fromMisoString k) v' obj---- | Register an event listener on given target.-addEventListener :: JSVal -- ^ Event target on which we want to register event listener- -> MisoString -- ^ Type of event to listen to (e.g. "click")- -> (JSVal -> JSM ()) -- ^ Callback which will be called when the event occurs, the event will be passed to it as a parameter.- -> JSM ()-addEventListener self name cb = do- _ <- self # "addEventListener" $ (name, asyncFunction (\_ _ [a] -> cb a))- pure ()---- | Registers an event listener on window-windowAddEventListener :: MisoString -- ^ Type of event to listen to (e.g. "click")- -> (JSVal -> JSM ()) -- ^ Callback which will be called when the event occurs, the event will be passed to it as a parameter.- -> JSM ()-windowAddEventListener name cb = do- win <- jsg "window"- addEventListener win name cb---- | Stop propagation of events-eventStopPropagation :: JSVal -> JSM ()-eventStopPropagation e = do- _ <- e # "stopPropagation" $ ()- pure ()---- | Prevent default event behavior-eventPreventDefault :: JSVal -> JSM ()-eventPreventDefault e = do- _ <- e # "preventDefault" $ ()- pure ()---- | Retrieves the height (in pixels) of the browser window viewport including, if rendered, the horizontal scrollbar. ----- See <https://developer.mozilla.org/en-US/docs/Web/API/Window/innerHeight>-windowInnerHeight :: JSM Int-windowInnerHeight =- fromJSValUnchecked =<< jsg "window" ! "innerHeight"---- | Retrieves the width (in pixels) of the browser window viewport including, if rendered, the vertical scrollbar.------ See <https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth>-windowInnerWidth :: JSM Int-windowInnerWidth =- fromJSValUnchecked =<< jsg "window" ! "innerWidth"---- | Retrieve high resolution time stamp------ See <https://developer.mozilla.org/en-US/docs/Web/API/Performance/now>-now :: JSM Double-now = fromJSValUnchecked =<< (jsg "performance" # "now" $ ())---- | Outputs a message to the web console------ See <https://developer.mozilla.org/en-US/docs/Web/API/Console/log>-consoleLog :: MisoString -> JSM ()-consoleLog v = do- _ <- jsg "console" # "log" $ [toJSString v]- pure ()---- | Console-logging-consoleLogJSVal :: JSVal -> JSM ()-consoleLogJSVal v = do- _ <- jsg "console" # "log" $ [v]- pure ()---- | Converts a JS object into a JSON string-stringify :: ToJSON json => json -> JSM MisoString-{-# INLINE stringify #-}-stringify j = do- v <- toJSVal (toJSON j)- fromJSValUnchecked =<< (jsg "JSON" # "stringify" $ [v])---- | Parses a MisoString-parse :: FromJSON json => JSVal -> JSM json-{-# INLINE parse #-}-parse jval = do- val <- fromJSValUnchecked =<< (jsg "JSON" # "parse" $ [jval])- case fromJSON val of- Success x -> pure x- Error y -> error y---- | Clear the document body. This is particularly useful to avoid--- creating multiple copies of your app when running in GHCJSi.-clearBody :: JSM ()-clearBody =- (jsg "document" ! "body" <# "innerHtml") [""]---- | Convert a JavaScript object to JSON-objectToJSON- :: JSVal -- ^ decodeAt :: [JSString]- -> JSVal -- ^ object with impure references to the DOM- -> JSM JSVal-objectToJSON = jsg2 "objectToJSON"---- | Retrieves a reference to document body.------ See <https://developer.mozilla.org/en-US/docs/Web/API/Document/body>-getBody :: JSM JSVal-getBody = jsg "document" ! "body"---- | Retrieves a reference to the document.------ See <https://developer.mozilla.org/en-US/docs/Web/API/Document>-getDoc :: JSM JSVal-getDoc = jsg "document"---- | Returns an Element object representing the element whose id property matches the specified string.------ See <https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById>-getElementById :: MisoString -> JSM JSVal-getElementById e = getDoc # "getElementById" $ [e]---- | Diff two virtual DOMs-diff'- :: OI.Object -- ^ current object- -> OI.Object -- ^ new object- -> JSVal -- ^ parent node- -> JSVal -- ^ document- -> JSM ()-diff' a b c d = () <$ jsg4 "diff" a b c d---- | Helper function for converting Integral types to JavaScript strings-integralToJSString :: Integral a => a -> MisoString-integralToJSString = pack . show . toInteger---- | Helper function for converting RealFloat types to JavaScript strings-realFloatToJSString :: RealFloat a => a -> MisoString-realFloatToJSString x = (pack . show) (realToFrac x :: Double)---- | Helper function for converting RealFloat types to JavaScript strings-jsStringToDouble :: MisoString -> Double-jsStringToDouble = read . unpack---- | Initialize event delegation from a mount point.-delegateEvent :: JSVal -> JSVal -> JSM JSVal -> JSM ()-delegateEvent mountPoint events getVTree = do- cb' <- function $ \_ _ [continuation] -> do- res <- getVTree- _ <- call continuation global res- pure ()- delegateEvent' mountPoint events cb'---- | Call 'delegateEvent' JavaScript function-delegateEvent' :: JSVal -> JSVal -> Function -> JSM ()-delegateEvent' mountPoint events cb = () <$ jsg3 "delegate" mountPoint events cb---- | Copies DOM pointers into virtual dom--- entry point into isomorphic javascript-copyDOMIntoVTree :: Bool -> JSVal -> JSVal -> JSM ()-copyDOMIntoVTree logLevel mountPoint a = () <$ jsg3 "copyDOMIntoVTree" logLevel mountPoint a---- TODO For now, we do not free callbacks when compiling with JSaddle---- | Pins down the current callbacks for clearing later-swapCallbacks :: JSM ()-swapCallbacks = pure ()---- | Releases callbacks registered by the virtual DOM.-releaseCallbacks :: JSM ()-releaseCallbacks = pure ()---- | Mock for callback registration-registerCallback :: JSVal -> JSM ()-registerCallback _ = pure ()---- | Fails silently if the element is not found.------ Analogous to @document.getElementById(id).focus()@.-focus :: MisoString -> JSM ()-focus a = () <$ jsg1 "callFocus" a---- | Fails silently if the element is not found.+-- Foreign Function Interface (FFI) utilities for interacting with JavaScript. ----- Analogous to @document.getElementById(id).blur()@-blur :: MisoString -> JSM ()-blur a = () <$ jsg1 "callBlur" a---- | Calls @document.getElementById(id).scrollIntoView()@-scrollIntoView :: MisoString -> JSM ()-scrollIntoView elId = do- el <- jsg "document" # "getElementById" $ [elId]- _ <- el # "scrollIntoView" $ ()- pure ()---- | Calls the @alert()@ function.-alert :: MisoString -> JSM ()-alert a = () <$ jsg1 "alert" a+----------------------------------------------------------------------------+module Miso.FFI+ ( -- ** Object+ set+ -- ** Performance+ , now+ -- ** Logging+ , consoleLog+ , consoleLog'+ , consoleError+ , consoleWarn+ -- ** DOM+ , getElementById+ , focus+ , blur+ , select+ , setSelectionRange+ , alert+ , getProperty+ , callFunction+ , castJSVal+ , removeChild+ -- ** Styles+ , addStyle+ , addStyleSheet+ -- * JS+ , addSrc+ , addScript+ , addScriptImportMap+ -- ** Callbacks+ , syncCallback+ , syncCallback1+ , asyncCallback+ , asyncCallback1+ , asyncCallback2+ -- ** Drawing+ , flush+ , setDrawingContext+ -- ** Window+ , windowInnerWidth+ , windowInnerHeight+ , locationReload+ -- ** Image+ , Image (..)+ , newImage+ -- ** Date+ , Date (..)+ , newDate+ , toLocaleString+ , getSeconds+ , getMilliseconds+ -- ** DOM Traversal+ , nextSibling+ , previousSibling+ -- ** Element+ , click+ , setValue+ -- ** File Input+ , files+ -- ** Navigator+ , isOnLine+ -- ** ArrayBuffer+ , ArrayBuffer (..)+ -- ** Blob+ , Blob (..)+ -- ** Uint8Array+ , Uint8Array (..)+ -- ** FormData+ , FormData (..)+ -- ** File+ , File (..)+ -- ** URLSearchParams+ , URLSearchParams (..)+ -- ** FileReader+ , FileReader (..)+ , newFileReader+ -- ** Fetch API+ , fetch+ , Response (..)+ -- ** Event+ , addEventListener+ , removeEventListener+ , dispatchEvent+ , newEvent+ , newCustomEvent+ , Event (..)+ , eventPreventDefault+ , eventStopPropagation+ -- ** Inline JS+ , inline+ -- ** Scroll+ , scrollIntoView+ -- ** SplitMix32+ , splitmix32+ -- ** Math.random()+ , mathRandom+ -- ** Model+ , mountComponent+ , unmountComponent+ , modelHydration+ ) where+-----------------------------------------------------------------------------+import Miso.FFI.Internal+-----------------------------------------------------------------------------
− src/Miso/FFI/History.hs
@@ -1,57 +0,0 @@--------------------------------------------------------------------------------- |--- Module : Miso.FFI.History--- Copyright : (C) 2016-2025 David M. Johnson--- License : BSD3-style (see the file LICENSE)--- Maintainer : David M. Johnson <code@dmj.io>--- Stability : experimental--- Portability : non-portable------------------------------------------------------------------------------module Miso.FFI.History- ( getWindowLocationHref- , go- , back- , forward- , pushState- , replaceState- ) where--import Control.Monad-import GHCJS.Types-import Language.Javascript.JSaddle-import Miso.String--getWindowLocationHref :: JSM MisoString-getWindowLocationHref = do- href <- fromJSVal =<< jsg "window" ! "location" ! "href"- case join href of- Nothing -> pure mempty- Just uri -> pure uri--getHistory :: JSM JSVal-getHistory = jsg "window" ! "history"--go :: Int -> JSM ()-go i = do- _ <- getHistory # "go" $ [i]- pure ()--back :: JSM ()-back = do- _ <- getHistory # "back" $ ()- pure ()--forward :: JSM ()-forward = do- _ <- getHistory # "forward" $ ()- pure ()--pushState :: MisoString -> JSM ()-pushState url = do- _ <- getHistory # "pushState" $ (jsNull, jsNull, url)- pure ()--replaceState :: MisoString -> JSM ()-replaceState url = do- _ <- getHistory # "replaceState" $ (jsNull, jsNull, url)- pure ()
+ src/Miso/FFI/Internal.hs view
@@ -0,0 +1,1171 @@+-----------------------------------------------------------------------------+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE CPP #-}+-----------------------------------------------------------------------------+{-# OPTIONS_GHC -fno-warn-orphans #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.FFI.Internal+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- Internal FFI functions for browser / device interaction.+--+----------------------------------------------------------------------------+module Miso.FFI.Internal+ ( -- * Callbacks+ syncCallback+ , syncCallback1+ , syncCallback2+ , asyncCallback+ , asyncCallback1+ , asyncCallback2+ -- * Events+ , addEventListener+ , removeEventListener+ , eventPreventDefault+ , eventStopPropagation+ -- * Window+ , windowAddEventListener+ , windowRemoveEventListener+ , windowInnerHeight+ , windowInnerWidth+ -- * Performance+ , now+ -- * Console+ , consoleWarn+ , consoleLog+ , consoleError+ , consoleLog'+ -- * JSON+ , eventJSON+ -- * Object+ , set+ , setValue+ -- * DOM+ , getBody+ , getDocument+ , getDrawingContext+ , getHydrationContext+ , getEventContext+ , getComponentContext+ , getElementById+ , removeChild+ , getHead+ , diff+ , nextSibling+ , previousSibling+ , getProperty+ , callFunction+ , castJSVal+ -- * Events+ , delegator+ , dispatchEvent+ , newEvent+ , newCustomEvent+ -- * Isomorphic+ , hydrate+ -- * Misc.+ , focus+ , blur+ , select+ , setSelectionRange+ , scrollIntoView+ , alert+ , locationReload+ -- * CSS+ , addStyle+ , addStyleSheet+ -- * JS+ , addSrc+ , addScript+ , addScriptImportMap+ -- * XHR+ , fetch+ , CONTENT_TYPE(..)+ -- * Drawing+ , setDrawingContext+ , flush+ -- * Image+ , Image (..)+ , newImage+ -- * Date+ , Date (..)+ , newDate+ , toLocaleString+ -- * Utils+ , getMilliseconds+ , getSeconds+ -- * Element+ , files+ , click+ -- * WebSocket+ , websocketConnect+ , websocketClose+ , websocketSend+ -- * SSE+ , eventSourceConnect+ , eventSourceClose+ -- * Blob+ , Blob (..)+ -- * FormData+ , FormData (..)+ -- * URLSearchParams+ , URLSearchParams (..)+ -- * File+ , File (..)+ -- * Uint8Array+ , Uint8Array (..)+ -- * ArrayBuffer+ , ArrayBuffer (..)+ -- * Navigator+ , geolocation+ , copyClipboard+ , getUserMedia+ , isOnLine+ -- * FileReader+ , FileReader (..)+ , newFileReader+ -- * Fetch API+ , Response (..)+ -- * Event+ , Event (..)+ -- * Class+ , populateClass+ , updateRef+ -- * Inline JS+ , inline+ -- * Randomness+ , splitmix32+ -- * Math+ , mathRandom+ -- * Crypto+ , getRandomValue+ -- * Model+ , mountComponent+ , unmountComponent+ , modelHydration+ ) where+-----------------------------------------------------------------------------+import Control.Monad (void, forM_, (<=<), when)+import Data.Map.Strict (Map)+import Data.Maybe+import Prelude hiding ((!!))+-----------------------------------------------------------------------------+import Miso.DSL+import Miso.String+-----------------------------------------------------------------------------+-- | Set property on object+set :: ToJSVal v => MisoString -> v -> Object -> IO ()+{-# INLINABLE set #-}+set k v o = do+ v' <- toJSVal v+ setProp (fromMisoString k) v' o+-----------------------------------------------------------------------------+-- | Get a property of a 'JSVal'+--+-- Example usage:+--+-- > Just (value :: String) <- fromJSVal =<< getProperty domRef "value"+getProperty :: JSVal -> MisoString -> IO JSVal+{-# INLINABLE getProperty #-}+getProperty = (!)+-----------------------------------------------------------------------------+-- | Calls a function on a 'JSVal'+--+-- Example usage:+--+-- > callFunction domRef "focus" ()+-- > callFunction domRef "setSelectionRange" (0, 3, "none")+callFunction :: (ToArgs args) => JSVal -> MisoString -> args -> IO JSVal+{-# INLINABLE callFunction #-}+callFunction = (#)+-----------------------------------------------------------------------------+-- | Marshalling of 'JSVal', useful for 'getProperty'+castJSVal :: (FromJSVal a) => JSVal -> IO (Maybe a)+{-# INLINABLE castJSVal #-}+castJSVal = fromJSVal+-----------------------------------------------------------------------------+-- | Register an event listener on given target.+addEventListener+ :: JSVal+ -- ^ Event target on which we want to register event listener+ -> MisoString+ -- ^ Type of event to listen to (e.g. "click")+ -> (JSVal -> IO ())+ -- ^ Callback which will be called when the event occurs,+ -- the event will be passed to it as a parameter.+ -> IO Function+{-# INLINABLE addEventListener #-}+addEventListener self name cb = do+#ifdef GHCJS_BOTH+ cb_ <- Function <$> syncCallback1 cb+#else+ cb_ <- Function <$> asyncCallback1 cb+#endif+ void $ self # "addEventListener" $ (name, cb_)+ pure cb_+-----------------------------------------------------------------------------+-- | Removes an event listener from given target.+removeEventListener+ :: JSVal+ -- ^ Event target from which we want to remove event listener+ -> MisoString+ -- ^ Type of event to listen to (e.g. "click")+ -> Function+ -- ^ Callback which will be called when the event occurs,+ -- the event will be passed to it as a parameter.+ -> IO ()+{-# INLINABLE removeEventListener #-}+removeEventListener self name cb =+ void $ self # "removeEventListener" $ (name, cb)+-----------------------------------------------------------------------------+-- | Removes an event listener from window+windowRemoveEventListener+ :: MisoString+ -- ^ Type of event to listen to (e.g. "click")+ -> Function+ -- ^ Callback which will be called when the event occurs,+ -- the event will be passed to it as a parameter.+ -> IO ()+{-# INLINABLE windowRemoveEventListener #-}+windowRemoveEventListener name cb = do+ win <- jsg "window"+ removeEventListener win name cb+-----------------------------------------------------------------------------+-- | Registers an event listener on window+windowAddEventListener+ :: MisoString+ -- ^ Type of event to listen to (e.g. "click")+ -> (JSVal -> IO ())+ -- ^ Callback which will be called when the event occurs,+ -- the event will be passed to it as a parameter.+ -> IO Function+{-# INLINABLE windowAddEventListener #-}+windowAddEventListener name cb = do+ win <- jsg "window"+ addEventListener win name cb+-----------------------------------------------------------------------------+-- | Stop propagation of events+eventStopPropagation :: JSVal -> IO ()+{-# INLINABLE eventStopPropagation #-}+eventStopPropagation e = do+ _ <- e # "stopPropagation" $ ()+ pure ()+-----------------------------------------------------------------------------+-- | Prevent default event behavior+eventPreventDefault :: JSVal -> IO ()+{-# INLINABLE eventPreventDefault #-}+eventPreventDefault e = do+ _ <- e # "preventDefault" $ ()+ pure ()+-----------------------------------------------------------------------------+-- | Retrieves the height (in pixels) of the browser window viewport including,+-- if rendered, the horizontal scrollbar.+--+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Window/innerHeight>+windowInnerHeight :: IO Int+{-# INLINABLE windowInnerHeight #-}+windowInnerHeight = fromJSValUnchecked =<< jsg "window" ! "innerHeight"+-----------------------------------------------------------------------------+-- | Retrieves the width (in pixels) of the browser window viewport including+-- if rendered, the vertical scrollbar.+--+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth>+windowInnerWidth :: IO Int+{-# INLINABLE windowInnerWidth #-}+windowInnerWidth =+ fromJSValUnchecked =<< jsg "window" ! "innerWidth"+-----------------------------------------------------------------------------+-- | Retrieve high resolution time stamp+--+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Performance/now>+now :: IO Double+{-# INLINABLE now #-}+now = fromJSValUnchecked =<< (jsg "performance" # "now" $ ())+-----------------------------------------------------------------------------+-- | Outputs a message to the web console+--+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Console/log>+--+-- Console logging of JavaScript strings.+consoleLog :: MisoString -> IO ()+{-# INLINABLE consoleLog #-}+consoleLog v = do+ _ <- jsg "console" # "log" $ [ms v]+ pure ()+-----------------------------------------------------------------------------+-- | Outputs a warning message to the web console+--+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Console/warn>+--+-- Console logging of JavaScript strings.+consoleWarn :: MisoString -> IO ()+{-# INLINABLE consoleWarn #-}+consoleWarn v = do+ _ <- jsg "console" # "warn" $ [ms v]+ pure ()+-----------------------------------------------------------------------------+-- | Outputs an error message to the web console+--+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Console/error>+--+-- Console logging of JavaScript strings.+consoleError :: MisoString -> IO ()+{-# INLINABLE consoleError #-}+consoleError v = do+ _ <- jsg "console" # "error" $ [ms v]+ pure ()+-----------------------------------------------------------------------------+-- | Console-logging of JSVal+consoleLog' :: ToArgs a => a -> IO ()+{-# INLINABLE consoleLog' #-}+consoleLog' args' = do+ args <- toArgs args'+ _ <- jsg "console" # "log" $ args+ pure ()+-----------------------------------------------------------------------------+-- | Convert a JavaScript object to JSON+-- JSONified representation of events+eventJSON+ :: JSVal -- ^ decodeAt :: [JSString]+ -> JSVal -- ^ object with impure references to the DOM+ -> IO JSVal+{-# INLINABLE eventJSON #-}+eventJSON x y = do+ moduleMiso <- jsg "miso"+ moduleMiso # "eventJSON" $ [x,y]+-----------------------------------------------------------------------------+-- | Used to update the JavaScript reference post-diff.+updateRef+ :: ToJSVal val+ => val+ -> val+ -> IO ()+{-# INLINABLE updateRef #-}+updateRef jsval1 jsval2 = do+ moduleMiso <- jsg "miso"+ void $ moduleMiso # "updateRef" $ (jsval1, jsval2)+-----------------------------------------------------------------------------+-- | Convenience function to write inline javascript.+--+-- Prefer this function over the use of `eval`.+--+-- This function takes as arguments a JavaScript object and makes the+-- keys available in the function body.+--+-- @+--+-- data Person = Person { name :: MisoString, age :: Int }+-- deriving stock (Generic)+-- deriving anyclass (ToJSVal, ToObject)+--+-- logNameGetAge :: Person -> IO Int+-- logNameGetAge = inline+-- """+-- console.log('name', name);+-- return age;+-- """+--+-- @+--+inline+ :: (FromJSVal return, ToObject object)+ => MisoString+ -> object+ -> IO return+{-# INLINABLE inline #-}+inline code o = do+ moduleMiso <- jsg "miso"+ Object obj <- toObject o+ fromJSValUnchecked =<< do+ moduleMiso # "inline" $ (code, obj)+-----------------------------------------------------------------------------+-- | Populate the 'Miso.Html.Property.classList' Set on the virtual DOM.+populateClass+ :: JSVal+ -- ^ Node+ -> [MisoString]+ -- ^ classes+ -> IO ()+{-# INLINABLE populateClass #-}+populateClass domRef classes = do+ moduleMiso <- jsg "miso"+ void $ moduleMiso # "populateClass" $ (domRef, classes)+-----------------------------------------------------------------------------+-- | Retrieves a reference to document body.+--+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Document/body>+getBody :: IO JSVal+{-# INLINABLE getBody #-}+getBody = do+ ctx <- getDrawingContext+ ctx # "getRoot" $ ()+-----------------------------------------------------------------------------+-- | Retrieves a reference to the document.+--+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Document>+getDocument :: IO JSVal+{-# INLINABLE getDocument #-}+getDocument = jsg "document"+-----------------------------------------------------------------------------+-- | Retrieves a reference to the drawing context.+--+-- This is a miso specific construct used to provide an identical interface+-- for both native (iOS / Android, etc.) and browser environments.+--+getDrawingContext :: IO JSVal+{-# INLINABLE getDrawingContext #-}+getDrawingContext = jsg "miso" ! "drawingContext"+-----------------------------------------------------------------------------+-- | Retrieves a reference to the event context.+--+-- This is a miso specific construct used to provide an identical interface+-- for both native (iOS / Android, etc.) and browser environments.+--+getEventContext :: IO JSVal+{-# INLINABLE getEventContext #-}+getEventContext = jsg "miso" ! "eventContext"+-----------------------------------------------------------------------------+-- | Retrieves a reference to the hydration context.+--+-- This is a miso specific construct used to provide an identical interface+-- for both native (iOS / Android, etc.) and browser environments.+--+getHydrationContext :: IO JSVal+{-# INLINABLE getHydrationContext #-}+getHydrationContext = jsg "miso" ! "hydrationContext"+-----------------------------------------------------------------------------+-- | Retrieves a reference to the Component context.+--+-- This is a miso specific construct used to provide an identical interface+-- for both native (iOS / Android, etc.) and browser environments.+--+getComponentContext :: IO JSVal+{-# INLINABLE getComponentContext #-}+getComponentContext = jsg "miso" ! "componentContext"+-----------------------------------------------------------------------------+-- | Returns an Element object representing the element whose id property matches+-- the specified string.+--+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById>+getElementById :: MisoString -> IO JSVal+{-# INLINABLE getElementById #-}+getElementById e = getDocument # "getElementById" $ [e]+-----------------------------------------------------------------------------+-- | Retrieves a reference to the renderer's "head" mount.+--+-- Calls @miso.drawingContext.getHead()@.+--+-- Note: custom renderers should implement this method.+--+-- @since 1.9.0.0+getHead :: IO JSVal+{-# INLINABLE getHead #-}+getHead = do+ context <- getDrawingContext+ context # "getHead" $ ()+-----------------------------------------------------------------------------+-- | Removes a child node from a parent node.+--+-- Calls @miso.drawingContext.removeChild(parent, child)@.+--+-- @since 1.9.0.0+removeChild :: JSVal -> JSVal -> IO ()+{-# INLINABLE removeChild #-}+removeChild parent child = do+ context <- getDrawingContext+ void $ context # "removeChild" $ (parent, child)+-----------------------------------------------------------------------------+-- | Diff two virtual DOMs+diff+ :: Object+ -- ^ current object+ -> Object+ -- ^ new object+ -> JSVal+ -- ^ parent node+ -> IO ()+{-# INLINABLE diff #-}+diff (Object a) (Object b) c = do+ moduleMiso <- jsg "miso"+ context <- getDrawingContext+ void $ moduleMiso # "diff" $ [a,b,c,context]+-----------------------------------------------------------------------------+-- | Initialize event delegation from a mount point.+delegator :: JSVal -> JSVal -> Bool -> IO JSVal -> IO ()+{-# INLINABLE delegator #-}+delegator mountPoint events debug getVTree = do+ ctx <- getEventContext+#ifdef WASM+ cb <- asyncCallback1 $ \continuation -> void (call continuation global =<< getVTree)+#else+ cb <- syncCallback1 $ \continuation -> void (call continuation global =<< getVTree)+#endif+ d <- toJSVal debug+ moduleMiso <- jsg "miso"+ void $ moduleMiso # "delegator" $ [mountPoint,events,cb,d,ctx]+-----------------------------------------------------------------------------+-- | Copies DOM pointers into virtual dom entry point into isomorphic javascript+--+-- See [hydration](https://en.wikipedia.org/wiki/Hydration_(web_development))+--+hydrate :: Bool -> JSVal -> JSVal -> IO JSVal+{-# INLINABLE hydrate #-}+hydrate logLevel mountPoint vtree = do+ ll <- toJSVal logLevel+ drawingContext <- getDrawingContext+ hydrationContext <- getHydrationContext+ moduleMiso <- jsg "miso"+ moduleMiso # "hydrate" $ (ll, mountPoint, vtree, hydrationContext, drawingContext)+-----------------------------------------------------------------------------+-- | Fails silently if the element is not found.+--+-- Analogous to @document.getElementById(id).focus()@.+focus :: MisoString -> IO ()+{-# INLINABLE focus #-}+focus x = void $ jsg "miso" # "callFocus" $ (x, 50 :: Int)+-----------------------------------------------------------------------------+-- | Fails silently if the element is not found.+--+-- Analogous to @document.getElementById(id).blur()@+blur :: MisoString -> IO ()+{-# INLINABLE blur #-}+blur x = void $ jsg "miso" # "callBlur" $ (x, 50 :: Int)+-----------------------------------------------------------------------------+-- | Fails silently if the element is not found.+--+-- Analogous to @document.querySelector('#' + id).select()@.+select :: MisoString -> IO ()+{-# INLINABLE select #-}+select x = void $ jsg "miso" # "callSelect" $ (x, 50 :: Int)+-----------------------------------------------------------------------------+-- | Fails silently if the element is not found.+--+-- Analogous to @document.querySelector('#' + id).setSelectionRange(start, end, \'none\')@.+setSelectionRange :: MisoString -> Int -> Int -> IO ()+{-# INLINABLE setSelectionRange #-}+setSelectionRange x start end = void $ jsg "miso" # "callSetSelectionRange" $ (x, start, end, 50 :: Int)+-----------------------------------------------------------------------------+-- | Calls @document.getElementById(id).scrollIntoView()@+scrollIntoView :: MisoString -> IO ()+{-# INLINABLE scrollIntoView #-}+scrollIntoView elId = do+ el <- jsg "document" # "getElementById" $ [elId]+ _ <- el # "scrollIntoView" $ ()+ pure ()+-----------------------------------------------------------------------------+-- | Calls the @alert()@ function.+alert :: MisoString -> IO ()+{-# INLINABLE alert #-}+alert a = () <$ jsg1 "alert" a+-----------------------------------------------------------------------------+-- | Calls the @location.reload()@ function.+locationReload :: IO ()+{-# INLINABLE locationReload #-}+locationReload = void $ jsg "location" # "reload" $ ([] :: [MisoString])+-----------------------------------------------------------------------------+-- | Appends a 'Miso.Html.Element.style_' element containing CSS to 'Miso.Html.Element.head_'+--+-- > addStyle "body { background-color: green; }"+--+-- > <head><style>body { background-color: green; }</style></head>+--+addStyle :: MisoString -> IO JSVal+{-# INLINABLE addStyle #-}+addStyle css = do+ context <- getDrawingContext+ head_ <- getHead+ style <- context # "createElement" $ ["style" :: MisoString]+ setField style "innerHTML" css+ void $ context # "appendChild" $ (head_, style)+ pure style+-----------------------------------------------------------------------------+-- | Appends a 'Miso.Html.Element.script_' element containing JS to 'Miso.Html.Element.head_'+--+-- > addScript False "function () { alert('hi'); }"+--+addScript :: Bool -> MisoString -> IO JSVal+{-# INLINABLE addScript #-}+addScript useModule js_ = do+ context <- getDrawingContext+ head_ <- getHead+ script <- context # "createElement" $ ["script" :: MisoString]+ when useModule $ setField script "type" ("module" :: MisoString)+ setField script "innerHTML" js_+ void $ context # "appendChild" $ (head_, script)+ pure script+-----------------------------------------------------------------------------+-- | Sets the @.value@ property on a 'DOMRef'.+--+-- Useful for resetting the @value@ property on an input element.+--+-- @+-- setValue domRef ("" :: MisoString)+-- @+--+setValue :: JSVal -> MisoString -> IO ()+{-# INLINABLE setValue #-}+setValue domRef value = setField domRef "value" value+-----------------------------------------------------------------------------+-- | Appends a 'Miso.Html.Element.script_' element containing a JS import map.+--+-- > addScript "{ \"import\" : { \"three\" : \"url\" } }"+--+addScriptImportMap :: MisoString -> IO JSVal+{-# INLINABLE addScriptImportMap #-}+addScriptImportMap impMap = do+ context <- getDrawingContext+ head_ <- getHead+ script <- context # "createElement" $ ["script" :: MisoString]+ setField script "type" ("importmap" :: MisoString)+ setField script "innerHTML" impMap+ void $ context # "appendChild" $ (head_, script)+ pure script+-----------------------------------------------------------------------------+-- | Appends a \<script\> element to 'Miso.Html.Element.head_'+--+-- > addSrc "https://example.com/script.js"+--+addSrc :: MisoString -> Bool -> IO JSVal+{-# INLINABLE addSrc #-}+addSrc url cacheBust = do+ context <- getDrawingContext+ head_ <- getHead+ link <- context # "createElement" $ ["script" :: MisoString]+ url_ <- appendTimestamp url cacheBust+ _ <- link # "setAttribute" $ ["src", url_ ]+ void $ context # "appendChild" $ (head_, link)+ pure link+-----------------------------------------------------------------------------+-- | Appends a StyleSheet 'Miso.Html.Element.link_' element to 'Miso.Html.Element.head_'+-- The 'Miso.Html.Element.link_' tag will contain a URL to a CSS file.+--+-- > addStyleSheet "https://cdn.jsdelivr.net/npm/todomvc-common@1.0.5/base.min.css"+--+-- > <head><link href="https://cdn.jsdelivr.net/npm/todomvc-common@1.0.5/base.min.css" ref="stylesheet"></head>+--+addStyleSheet :: MisoString -> Bool -> IO JSVal+{-# INLINABLE addStyleSheet #-}+addStyleSheet url cacheBust = do+ context <- getDrawingContext+ head_ <- getHead+ link <- context # "createElement" $ ["link" :: MisoString]+ _ <- link # "setAttribute" $ ["rel","stylesheet" :: MisoString]+ url_ <- appendTimestamp url cacheBust + _ <- link # "setAttribute" $ ["href", url_ ]+ void $ context # "appendChild" $ (head_, link)+ pure link+-----------------------------------------------------------------------------+-- | Helper for cache busting+appendTimestamp :: MisoString -> Bool -> IO MisoString+{-# INLINABLE appendTimestamp #-}+appendTimestamp url = \case+ True -> do+ ts <- fromJSValUnchecked =<< do jsg "Date" # "now" $ ()+ pure (url <> "?v=" <> ms (ts :: Double))+ False ->+ pure url+-----------------------------------------------------------------------------+-- | Retrieve JSON via Fetch API+--+-- Basic GET of JSON using Fetch API, will be expanded upon.+--+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API>+--+fetch+ :: (FromJSVal success, FromJSVal error)+ => MisoString+ -- ^ url+ -> MisoString+ -- ^ method+ -> Maybe JSVal+ -- ^ body+ -> [(MisoString, MisoString)]+ -- ^ headers+ -> (Response success -> IO ())+ -- ^ successful callback+ -> (Response error -> IO ())+ -- ^ errorful callback+ -> CONTENT_TYPE+ -- ^ content type+ -> IO ()+{-# INLINABLE fetch #-}+fetch url method maybeBody requestHeaders successful errorful type_ = do+ successful_ <- toJSVal =<< asyncCallback1 (successful <=< fromJSValUnchecked)+ errorful_ <- toJSVal =<< asyncCallback1 (errorful <=< fromJSValUnchecked)+ moduleMiso <- jsg "miso"+ url_ <- toJSVal url+ method_ <- toJSVal method+ body_ <- toJSVal maybeBody+ Object headers_ <- do+ o <- create+ forM_ requestHeaders $ \(k,v) -> set k v o+ pure o+ typ <- toJSVal type_+ void $ moduleMiso # "fetchCore" $+ [ url_+ , method_+ , body_+ , headers_+ , successful_+ , errorful_+ , typ+ ]+-----------------------------------------------------------------------------+-- | List of possible content types that are available for use with the fetch API+data CONTENT_TYPE+ = JSON+ | ARRAY_BUFFER+ | TEXT+ | BLOB+ | BYTES+ | FORM_DATA+ | NONE+ deriving (Show, Eq)+-----------------------------------------------------------------------------+instance ToJSVal CONTENT_TYPE where+ toJSVal = \case+ JSON ->+ toJSVal ("json" :: MisoString)+ ARRAY_BUFFER ->+ toJSVal ("arrayBuffer" :: MisoString)+ TEXT ->+ toJSVal ("text" :: MisoString)+ BLOB ->+ toJSVal ("blob" :: MisoString)+ BYTES ->+ toJSVal ("bytes" :: MisoString)+ FORM_DATA ->+ toJSVal ("formData" :: MisoString)+ NONE ->+ toJSVal ("none" :: MisoString)+ {-# INLINE toJSVal #-}+-----------------------------------------------------------------------------+-- | Flush is used to force a draw of the render tree. This is currently+-- only used when targeting platforms other than the browser (like mobile).+flush :: IO ()+{-# INLINABLE flush #-}+flush = do+ context <- getDrawingContext+ void $ context # "flush" $ ([] :: [JSVal])+-----------------------------------------------------------------------------+-- | Type that holds an [Image](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img).+newtype Image = Image JSVal+ deriving (ToJSVal, ToObject)+-----------------------------------------------------------------------------+instance FromJSVal Image where+ fromJSVal = pure . pure . Image+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+-- | Smart constructor for building a t'Image' w/ 'Miso.Html.Property.src_' 'Miso.Types.Attribute'.+newImage :: MisoString -> IO Image+{-# INLINABLE newImage #-}+newImage url = do+ img <- new (jsg "Image") ([] :: [MisoString])+ setField img "src" url+ pure (Image img)+-----------------------------------------------------------------------------+-- | Used to select a drawing context. Users can override the default DOM renderer+-- by implementing their own Context, and exporting it to the global scope. This+-- opens the door to different rendering engines, ala [miso-lynx](https://github.com/haskell-miso/miso-lynx).+setDrawingContext :: MisoString -> IO ()+{-# INLINABLE setDrawingContext #-}+setDrawingContext rendererName =+ void $ jsg "miso" # "setDrawingContext" $ [rendererName]+-----------------------------------------------------------------------------+-- | The [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) type+newtype Date = Date JSVal+ deriving (ToJSVal, ToObject, Eq)+-----------------------------------------------------------------------------+-- | Smart constructor for a t'Date'+newDate :: IO Date+{-# INLINABLE newDate #-}+newDate = Date <$> new (jsg "Date") ([] :: [MisoString])+-----------------------------------------------------------------------------+-- | Date conversion function to produce a locale+toLocaleString :: Date -> IO MisoString+{-# INLINABLE toLocaleString #-}+toLocaleString date = fromJSValUnchecked =<< do+ date # "toLocaleString" $ ()+-----------------------------------------------------------------------------+-- | Retrieves current milliseconds from t'Date'+getMilliseconds :: Date -> IO Double+{-# INLINABLE getMilliseconds #-}+getMilliseconds date =+ fromJSValUnchecked =<< do+ date # "getMilliseconds" $ ([] :: [MisoString])+-----------------------------------------------------------------------------+-- | Retrieves current seconds from t'Date'+getSeconds :: Date -> IO Double+{-# INLINABLE getSeconds #-}+getSeconds date =+ fromJSValUnchecked =<< do+ date # "getSeconds" $ ([] :: [MisoString])+-----------------------------------------------------------------------------+-- | Fetch next sibling DOM node+--+-- @since 1.9.0.0+nextSibling :: JSVal -> IO JSVal+{-# INLINABLE nextSibling #-}+nextSibling domRef = domRef ! "nextSibling"+-----------------------------------------------------------------------------+-- | Fetch previous sibling DOM node+--+-- @since 1.9.0.0+previousSibling :: JSVal -> IO JSVal+{-# INLINABLE previousSibling #-}+previousSibling domRef = domRef ! "previousSibling"+-----------------------------------------------------------------------------+-- | When working with @\<input type="file"\>@, this is useful for+-- extracting out the selected files.+--+-- @+-- update (InputClicked inputElement) = withSink $ \\sink -> do+-- files_ <- files inputElement+-- forM_ files_ $ \\file -> sink (Upload file)+-- update (Upload file) = do+-- fetch \"https://localhost:8080\/upload\" \"POST\" (Just file) []+-- Successful Errorful+-- @+--+-- @since 1.9.0.0+files :: JSVal -> IO [JSVal]+{-# INLINABLE files #-}+files domRef = fromJSValUnchecked =<< domRef ! "files"+-----------------------------------------------------------------------------+-- | Simulates a click event+--+-- > button & click ()+--+-- @since 1.9.0.0+click :: () -> JSVal -> IO ()+{-# INLINABLE click #-}+click () domRef = void $ domRef # "click" $ ([] :: [MisoString])+-----------------------------------------------------------------------------+-- | Get Camera on user's device+--+-- <https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia>+--+getUserMedia+ :: Bool+ -- ^ video+ -> Bool+ -- ^ audio+ -> (JSVal -> IO ())+ -- ^ successful+ -> (JSVal -> IO ())+ -- ^ errorful+ -> IO ()+{-# INLINABLE getUserMedia #-}+getUserMedia video audio successful errorful = do+ params <- create+ set "video" video params+ set "audio" audio params+ devices <- jsg "navigator" ! "mediaDevices"+ promise <- devices # "getUserMedia" $ [params]+ successfulCallback <- asyncCallback1 successful+ void $ promise # "then" $ [successfulCallback]+ errorfulCallback <- asyncCallback1 errorful+ void $ promise # "catch" $ [errorfulCallback]+-----------------------------------------------------------------------------+-- | Copy clipboard+--+-- <https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia>+--+copyClipboard+ :: MisoString+ -- ^ Text to copy+ -> IO ()+ -- ^ successful+ -> (JSVal -> IO ())+ -- ^ errorful+ -> IO ()+{-# INLINABLE copyClipboard #-}+copyClipboard txt successful errorful = do+ clipboard <- jsg "navigator" ! "clipboard"+ promise <- clipboard # "writeText" $ [txt]+ successfulCallback <- asyncCallback successful+ void $ promise # "then" $ [successfulCallback]+ errorfulCallback <- asyncCallback1 errorful+ void $ promise # "catch" $ [errorfulCallback]+-----------------------------------------------------------------------------+-- | Establishes a @WebSocket@ connection+websocketConnect+ :: MisoString+ -> IO ()+ -> (JSVal -> IO ())+ -> Maybe (JSVal -> IO ())+ -> Maybe (JSVal -> IO ())+ -> Maybe (JSVal -> IO ())+ -> Maybe (JSVal -> IO ())+ -> (JSVal -> IO ())+ -> Bool+ -> IO JSVal+{-# INLINABLE websocketConnect #-}+websocketConnect+ url onOpen onClose+ onMessageText onMessageJSON+ onMessageBLOB onMessageArrayBuffer+ onError textOnly = do+ url_ <- toJSVal url+ onOpen_ <- toJSVal =<< asyncCallback onOpen+ onClose_ <- toJSVal =<< asyncCallback1 onClose+ onMessageText_ <- withMaybe onMessageText+ onMessageJSON_ <- withMaybe onMessageJSON+ onMessageBLOB_ <- withMaybe onMessageBLOB+ onMessageArrayBuffer_ <- withMaybe onMessageArrayBuffer+ onError_ <- toJSVal =<< asyncCallback1 onError+ textOnly_ <- toJSVal textOnly+ jsg "miso" # "websocketConnect" $+ [ url_+ , onOpen_+ , onClose_+ , onMessageText_+ , onMessageJSON_+ , onMessageBLOB_+ , onMessageArrayBuffer_+ , onError_+ , textOnly_+ ]+ where+ withMaybe Nothing = pure jsNull+ withMaybe (Just f) = asyncCallback1 f+-----------------------------------------------------------------------------+websocketClose :: JSVal -> IO ()+{-# INLINABLE websocketClose #-}+websocketClose websocket = void $ do+ jsg "miso" # "websocketClose" $ [websocket]+-----------------------------------------------------------------------------+websocketSend :: JSVal -> JSVal -> IO ()+{-# INLINABLE websocketSend #-}+websocketSend websocket message = void $ do+ jsg "miso" # "websocketSend" $ [websocket, message]+-----------------------------------------------------------------------------+eventSourceConnect+ :: MisoString+ -> IO ()+ -> Maybe (JSVal -> IO ())+ -> Maybe (JSVal -> IO ())+ -> (JSVal -> IO ())+ -> Bool+ -> IO JSVal+{-# INLINABLE eventSourceConnect #-}+eventSourceConnect url onOpen onMessageText onMessageJSON onError textOnly = do+ onOpen_ <- asyncCallback onOpen+ onMessageText_ <- withMaybe onMessageText+ onMessageJSON_ <- withMaybe onMessageJSON+ onError_ <- asyncCallback1 onError+ textOnly_ <- toJSVal textOnly+ jsg "miso" # "eventSourceConnect" $+ (url, onOpen_, onMessageText_, onMessageJSON_, onError_, textOnly_)+ where+ withMaybe Nothing = pure jsNull+ withMaybe (Just f) = toJSVal =<< asyncCallback1 f+-----------------------------------------------------------------------------+eventSourceClose :: JSVal -> IO ()+{-# INLINABLE eventSourceClose #-}+eventSourceClose eventSource = void $ do+ jsg "miso" # "eventSourceClose" $ [eventSource]+-----------------------------------------------------------------------------+-- | Navigator function to query the current online status of the user's computer+--+-- See [navigator.onLine](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine)+--+isOnLine :: IO Bool+{-# INLINABLE isOnLine #-}+isOnLine = fromJSValUnchecked =<< jsg "navigator" ! "onLine"+-----------------------------------------------------------------------------+-- | [Blob](https://developer.mozilla.org/en-US/docs/Web/API/FormData)+newtype Blob = Blob JSVal+ deriving (ToJSVal, Eq)+-----------------------------------------------------------------------------+instance FromJSVal Blob where+ fromJSVal = pure . pure . Blob+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+-- | [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData)+newtype FormData = FormData JSVal+ deriving (ToJSVal, Eq)+-----------------------------------------------------------------------------+instance FromJSVal FormData where+ fromJSVal = pure . pure . FormData+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+instance FromJSVal ArrayBuffer where+ fromJSVal = pure . pure . ArrayBuffer+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+-- | [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/API/ArrayBuffer)+newtype ArrayBuffer = ArrayBuffer JSVal+ deriving (Eq, ToJSVal)+-----------------------------------------------------------------------------+geolocation :: (JSVal -> IO ()) -> (JSVal -> IO ()) -> IO ()+{-# INLINABLE geolocation #-}+geolocation successful errorful = do+ geo <- jsg "navigator" ! "geolocation"+ cb1 <- asyncCallback1 successful+ cb2 <- asyncCallback1 errorful+ void $ geo # "getCurrentPosition" $ (cb1, cb2)+-----------------------------------------------------------------------------+-- | [File](https://developer.mozilla.org/en-US/docs/Web/API/File)+newtype File = File JSVal+ deriving (ToJSVal, ToObject, Eq)+-----------------------------------------------------------------------------+instance FromJSVal File where+ fromJSVal = pure . pure . File+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+-- | [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/API/Uint8Array)+newtype Uint8Array = Uint8Array JSVal+ deriving ToJSVal+-----------------------------------------------------------------------------+instance FromJSVal Uint8Array where+ fromJSVal = pure . pure . Uint8Array+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+-- | [FileReader](https://developer.mozilla.org/en-US/docs/Web/API/FileReader)+newtype FileReader = FileReader JSVal+ deriving (ToJSVal, ToObject, Eq)+-----------------------------------------------------------------------------+instance FromJSVal FileReader where+ fromJSVal = pure . pure . FileReader+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+-- | [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)+newtype URLSearchParams = URLSearchParams JSVal+ deriving (ToJSVal, ToObject, Eq)+-----------------------------------------------------------------------------+instance FromJSVal URLSearchParams where+ fromJSVal = pure . pure . URLSearchParams+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+-- | Smart constructor for building a t'FileReader'+newFileReader :: IO FileReader+{-# INLINABLE newFileReader #-}+newFileReader = do+ reader <- new (jsg "FileReader") ([] :: [MisoString])+ pure (FileReader reader)+-----------------------------------------------------------------------------+-- | Type returned from a 'fetch' request+data Response body+ = Response+ { status :: Maybe Int+ -- ^ HTTP status code+ , headers :: Map MisoString MisoString+ -- ^ Response headers+ , errorMessage :: Maybe MisoString+ -- ^ Optional error message+ , body :: body+ -- ^ Response body+ }+-----------------------------------------------------------------------------+instance Functor Response where+ fmap f response@Response { body } = response { body = f body }+ {-# INLINE fmap #-}+-----------------------------------------------------------------------------+instance FromJSVal body => FromJSVal (Response body) where+ fromJSVal o = do+ status_ <- fromJSVal =<< getProp "status" (Object o)+ headers_ <- fromJSVal =<< getProp "headers" (Object o)+ errorMessage_ <- fromJSVal =<< getProp "error" (Object o)+ body_ <- fromJSVal =<< getProp "body" (Object o)+ pure (Response <$> status_ <*> headers_ <*> errorMessage_ <*> body_)+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+-- | [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event)+newtype Event = Event JSVal+ deriving (ToJSVal, Eq)+-----------------------------------------------------------------------------+instance FromJSVal Event where+ fromJSVal = pure . Just . Event+ {-# INLINE fromJSVal #-}+-----------------------------------------------------------------------------+-- | Invokes [document.dispatchEvent](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent)+--+-- @+-- update ChangeTheme = io_ $ do+-- themeEvent <- newEvent "basecoat:theme"+-- dispatchEvent themeEvent+-- @+--+dispatchEvent :: Event -> IO ()+{-# INLINABLE dispatchEvent #-}+dispatchEvent event = do+ doc <- getDocument+ _ <- doc # "dispatchEvent" $ [event]+ pure ()+-----------------------------------------------------------------------------+-- | Creates a new [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event)+--+-- @+-- update ChangeTheme = io_ $ do+-- themeEvent <- newEvent "basecoat:theme"+-- dispatchEvent themeEvent+-- @+--+newEvent :: ToArgs args => args -> IO Event+{-# INLINABLE newEvent #-}+newEvent args = Event <$> new (jsg "Event") args+-----------------------------------------------------------------------------+-- | Creates a new [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event/CustomEvent)+--+-- @+-- update ToggleSidebar = io_ $ do+-- themeEvent <- newCustomEvent "basecoat:sidebar"+-- dispatchEvent themeEvent+-- @+--+newCustomEvent :: ToArgs args => args -> IO Event+{-# INLINABLE newCustomEvent #-}+newCustomEvent args = Event <$> new (jsg "CustomEvent") args+-----------------------------------------------------------------------------+-- | Uses the 'splitmix' function to generate a PRNG.+--+splitmix32 :: Double -> IO JSVal+{-# INLINABLE splitmix32 #-}+splitmix32 x = jsg "miso" # "splitmix32" $ [x]+-----------------------------------------------------------------------------+-- | Uses the 'Math.random()' function.+--+mathRandom :: IO Double+{-# INLINABLE mathRandom #-}+mathRandom = fromJSValUnchecked =<< do+ jsg "miso" # "mathRandom" $ ()+-----------------------------------------------------------------------------+-- | Uses the first element of 'crypto.getRandomValues()'.+--+getRandomValue :: IO Double+{-# INLINABLE getRandomValue #-}+getRandomValue = fromJSValUnchecked =<< do+ jsg "miso" # "getRandomValues" $ ()+-----------------------------------------------------------------------------+-- | Abstract over model hydration+modelHydration :: Int -> Object -> IO ()+{-# INLINABLE modelHydration #-}+modelHydration vcompId model_ = do+ comp <- getComponentContext+ void $ comp # "modelHydration" $ (vcompId, model_)+-----------------------------------------------------------------------------+-- | Abstract over Component mounting+mountComponent :: Int -> Object -> IO ()+{-# INLINABLE mountComponent #-}+mountComponent vcompId model_ = do+ comp <- getComponentContext+ void $ comp # "mountComponent" $ (vcompId, model_)+-----------------------------------------------------------------------------+-- | Abstract over Component unmounting+unmountComponent :: Int -> IO ()+{-# INLINABLE unmountComponent #-}+unmountComponent vcompId = do+ comp <- getComponentContext+ void $ comp # "unmountComponent" $ [vcompId]+-----------------------------------------------------------------------------
+ src/Miso/FFI/QQ.hs view
@@ -0,0 +1,140 @@+-----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveLift #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE TemplateHaskellQuotes #-}+-----------------------------------------------------------------------------+{-# OPTIONS_GHC -Wno-duplicate-exports #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.FFI.QQ+-- Copyright : (C) 2016-2026 David M. Johnson (@dmjio)+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- A QuasiQuoter for `inline-js` functionality.+--+-- @+--+-- {-# LANGUAGE QuasiQuotes #-}+--+-- import Miso.FFI.QQ (js)+--+-- fac :: Int -> IO Int+-- fac n = [js|+-- let x = 1;+-- for (i = 1; i <= ${n}; i++) {+-- x *= i;+-- }+-- return x;+-- |]+--+-- @+--+----------------------------------------------------------------------------+module Miso.FFI.QQ+ ( js+ ) where+----------------------------------------------------------------------------+import Control.Applicative+import Data.Data+import Control.Monad+import System.IO.Unsafe (unsafePerformIO)+import Language.Haskell.TH.Lib+import Language.Haskell.TH.Quote+import Language.Haskell.TH.Syntax+----------------------------------------------------------------------------+import Miso.String (MisoString)+import Miso.Util.Lexer+import Miso.DSL+import qualified Miso.String as MS+import qualified Miso.FFI as FFI+----------------------------------------------------------------------------+-- | QuasiQuoter for specifying inline JavaScript.+--+js :: QuasiQuoter+js = QuasiQuoter+ { quoteExp = \s -> dataToExpQ (withString `extQ` inlineJS) s+ , quotePat = \_ -> fail "quotePat: not implemented"+ , quoteType = \_ -> fail "quoteType: not implemented"+ , quoteDec = \_ -> fail "quoteDec: not implemented"+ }+----------------------------------------------------------------------------+inlineJS :: String -> Maybe (Q Exp)+inlineJS jsString = pure $ do+ found <- typeCheck vars+ kvs <- forM found $ \(var, key) -> do+ k <- [| MS.pack $(stringE (MS.unpack key)) |]+ let v = mkName (MS.unpack var)+ val <- [| unsafePerformIO (toJSVal $(varE v)) :: JSVal |]+ pure $ tupE [ pure k, pure val ]+ [| do o <- createWith ($(listE kvs) :: [(MisoString, JSVal)])+ FFI.inline $(stringE (MS.unpack (formatVars (MS.pack jsString) found)))+ o+ |] where+ vars = getVariables (MS.pack jsString)+----------------------------------------------------------------------------+extQ :: (Typeable a, Typeable b) => (a -> c) -> (b -> c) -> a -> c+extQ f g a = maybe (f a) g (cast a)+----------------------------------------------------------------------------+withString :: (Quote m, Typeable a) => a -> Maybe (m Exp)+withString a = liftString <$> cast a+----------------------------------------------------------------------------+-- | Use `isPrefixOf` as you traverse the string in lex order and do a replace+formatVars :: MisoString -> [(MisoString, MisoString)] -> MisoString+formatVars s [] = s+formatVars s table@((var,key):xs) =+ case MS.uncons s of+ Nothing ->+ mempty+ Just ('$', cs) -> do+ let needle = "{" <> var <> "}"+ if needle `MS.isPrefixOf` cs+ then+ formatVars (key <> MS.drop (MS.length needle) cs) xs+ else+ formatVars cs table+ Just (c,cs) ->+ MS.cons c (formatVars cs table)+----------------------------------------------------------------------------+keys :: [MisoString]+keys = do+ (x,y) <- (,) <$> ['a'..'z'] <*> ['0'..'9']+ pure (MS.pack [x,y])+----------------------------------------------------------------------------+typeCheck :: [MisoString] -> Q [(MisoString, MisoString)]+typeCheck vars = do+ forM (Prelude.zip vars keys) $ \(var, key) ->+ lookupValueName (MS.unpack var) >>= \case+ Nothing -> fail (MS.unpack var <> " is not in scope")+ Just _ -> pure (var, key)+---------------------------------------------------------------------------+getVariables :: MisoString -> [MisoString]+getVariables s =+ case runLexer lexer (mkStream s) of+ Left _ -> mempty+ Right (xs,_) -> xs+ where+ varLexer :: Lexer MisoString+ varLexer = do+ void (string "${")+ xs <- some $ satisfy (/= '}')+ void (char '}')+ pure (MS.pack xs)++ anything :: Lexer MisoString+ anything = mempty <$ satisfy (const True)++ lexer :: Lexer [MisoString]+ lexer = Prelude.filter (/="") <$>+ many (varLexer <|> anything)+----------------------------------------------------------------------------
− src/Miso/FFI/SSE.hs
@@ -1,39 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE LambdaCase #-}--------------------------------------------------------------------------------- |--- Module : Miso.FFI.SSE--- Copyright : (C) 2016-2025 David M. Johnson--- License : BSD3-style (see the file LICENSE)--- Maintainer : David M. Johnson <code@dmj.io>--- Stability : experimental--- Portability : non-portable------------------------------------------------------------------------------module Miso.FFI.SSE- ( EventSource(..)- , data'- , new- , addEventListener- ) where--import GHCJS.Types--import Miso.FFI (JSM)-import qualified Miso.FFI as FFI-import Miso.String--import qualified Language.Javascript.JSaddle as JSaddle-import Language.Javascript.JSaddle hiding (new)--newtype EventSource = EventSource JSVal--data' :: JSVal -> JSM JSVal-data' v = v ! ("data" :: JSString)--new :: MisoString -> JSM EventSource-new url = EventSource <$> JSaddle.new (jsg ("EventSource" :: JSString)) [url]--addEventListener :: EventSource -> MisoString -> (JSVal -> JSM ()) -> JSM ()-addEventListener (EventSource s) = FFI.addEventListener s
− src/Miso/FFI/Storage.hs
@@ -1,55 +0,0 @@--------------------------------------------------------------------------------- |--- Module : Miso.FFI.Storage--- Copyright : (C) 2016-2025 David M. Johnson--- License : BSD3-style (see the file LICENSE)--- Maintainer : David M. Johnson <code@dmj.io>--- Stability : experimental--- Portability : non-portable------------------------------------------------------------------------------module Miso.FFI.Storage- ( Storage- , localStorage- , sessionStorage- , getItem- , removeItem- , setItem- , length- , clear- ) where--import GHCJS.Types-import Prelude hiding (length)--import Language.Javascript.JSaddle ((!), (#), JSM, fromJSValUnchecked, jsg)-import Miso.String hiding (length)--newtype Storage = Storage JSVal--localStorage :: JSM Storage-localStorage = Storage <$> (jsg "window" ! "localStorage")--sessionStorage :: JSM Storage-sessionStorage = Storage <$> (jsg "window" ! "sessionStorage")--getItem :: Storage -> MisoString -> JSM JSVal-getItem (Storage s) key =- s # "getItem" $ [key]--removeItem :: Storage -> MisoString -> JSM ()-removeItem (Storage s) key = do- _ <- s # "removeItem" $ [key]- pure ()--setItem :: Storage -> MisoString -> MisoString -> JSM ()-setItem (Storage s) key val = do- _ <- s # "setItem" $ (key, val)- pure ()--length :: Storage -> JSM Int-length (Storage s) = fromJSValUnchecked =<< s ! "length"--clear :: Storage -> JSM ()-clear (Storage s) = do- _ <- s # "clear" $ ()- pure ()
− src/Miso/FFI/WebSocket.hs
@@ -1,68 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE LambdaCase #-}--------------------------------------------------------------------------------- |--- Module : Miso.FFI.WebSocket--- Copyright : (C) 2016-2025 David M. Johnson--- License : BSD3-style (see the file LICENSE)--- Maintainer : David M. Johnson <code@dmj.io>--- Stability : experimental--- Portability : non-portable------------------------------------------------------------------------------module Miso.FFI.WebSocket- ( Socket(..)- , create- , socketState- , send- , close- , addEventListener- , data'- , wasClean- , code- , reason- ) where--import GHCJS.Types--import Language.Javascript.JSaddle hiding (create)--import Miso.FFI (JSM)-import qualified Miso.FFI as FFI-import Miso.String-import Miso.WebSocket--newtype Socket = Socket JSVal--create :: MisoString -> JSVal -> JSM Socket-create url protocols = Socket <$> new (jsg ("WebSocket" :: JSString)) (url, protocols)--socketState :: Socket -> JSM Int-socketState (Socket s) = fromJSValUnchecked =<< s ! ("readyState" :: JSString)--send :: Socket -> MisoString -> JSM ()-send (Socket s) msg = do- _ <- s # ("send" :: JSString) $ [msg]- pure ()--close :: Socket -> JSM ()-close (Socket s) = do- _ <- s # ("close" :: JSString) $ ([] :: [JSString])- pure ()--addEventListener :: Socket -> MisoString -> (JSVal -> JSM ()) -> JSM ()-addEventListener (Socket s) name cb = do- FFI.addEventListener s name cb--data' :: JSVal -> JSM JSVal-data' v = v ! ("data" :: JSString)--wasClean :: JSVal -> JSM WasClean-wasClean v = WasClean <$> (fromJSValUnchecked =<< v ! ("wasClean" :: JSString))--code :: JSVal -> JSM Int-code v = fromJSValUnchecked =<< v ! ("code" :: JSString)--reason :: JSVal -> JSM Reason-reason v = Reason <$> (fromJSValUnchecked =<< v ! ("reason" :: JSString))
+ src/Miso/Fetch.hs view
@@ -0,0 +1,642 @@+-----------------------------------------------------------------------------+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Fetch+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- Interface to the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)+-- for making HTTP requests.+--+-- Refer to the miso README if you want to automatically interact with a Servant+-- API.+--+----------------------------------------------------------------------------+module Miso.Fetch+ ( -- ** JSON+ getJSON+ , postJSON+ , postJSON'+ , putJSON+ -- ** Text+ , getText+ , postText+ , putText+ -- ** Blob+ , getBlob+ , postBlob+ , putBlob+ -- ** FormData+ , getFormData+ , postFormData+ , putFormData+ -- ** Uint8Array+ , getUint8Array+ , postUint8Array+ , putUint8Array+ -- ** Image+ , postImage+ , putImage+ -- ** ArrayBuffer+ , getArrayBuffer+ , postArrayBuffer+ , putArrayBuffer+ -- ** Header helpers+ , accept+ , contentType+ , applicationJSON+ , textPlain+ , formData+ -- ** Types+ , Body+ , Response (..)+ , CONTENT_TYPE (..)+ -- ** Internal+ , fetch+ ) where+----------------------------------------------------------------------------+import Miso.JSON+import qualified Data.Map.Strict as M+----------------------------------------------------------------------------+import Miso.DSL (toJSVal, FromJSVal(..), JSVal)+import qualified Miso.FFI.Internal as FFI+import Miso.Effect (Effect, withSink)+import Miso.String (MisoString, ms)+import Miso.Util ((=:))+import Miso.FFI.Internal (Response(..), Blob, FormData, ArrayBuffer, Uint8Array, Image, fetch, CONTENT_TYPE(..))+----------------------------------------------------------------------------+-- | Retrieves JSON using the Fetch API.+--+-- See <https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API>+--+-- @+-- data Action+-- = FetchGitHub+-- | SetGitHub GitHub+-- | ErrorHandler MisoString+-- deriving (Show, Eq)+--+-- updateModel :: Action -> Effect Model Action+-- updateModel = \case+-- FetchGitHub -> getJSON "https://api.github.com" [] SetGitHub ErrorHandler+-- SetGitHub apiInfo -> info ?= apiInfo+-- ErrorHandler msg -> io_ (consoleError msg)+-- @+--+getJSON+ :: (FromJSON body, FromJSVal error)+ => MisoString+ -- ^ url+ -> [(MisoString, MisoString)]+ -- ^ headers+ -> (Response body -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+getJSON url headers_ successful errorful =+ withSink $ \sink ->+ FFI.fetch url "GET" Nothing jsonHeaders+ (handleJSON sink)+ (sink . errorful)+ JSON -- dmj: expected return type+ where+ jsonHeaders = biasHeaders headers_ [accept =: applicationJSON]+ handleJSON sink resp@Response {..} =+ fmap fromJSON <$> fromJSVal body >>= \case+ Nothing -> do+ err <- fromJSValUnchecked body+ sink $ errorful $ Response+ { body = err+ , errorMessage = Just "Not a valid JSON object"+ , ..+ }+ Just (Success result) ->+ sink $ successful resp { body = result }+ Just (Error msg) -> do+ err <- fromJSValUnchecked body+ sink $ errorful $ Response+ { body = err+ , errorMessage = Just (ms msg)+ , ..+ }+----------------------------------------------------------------------------+-- | Sends a POST request with JSON encoded data.+postJSON+ :: (FromJSVal error, ToJSON body)+ => MisoString+ -- ^ url+ -> body+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response () -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+postJSON url body_ headers_ successful errorful =+ withSink $ \sink -> do+ bodyVal <- toJSVal (encode body_)+ FFI.fetch url "POST" (Just bodyVal) jsonHeaders_+ (sink . successful)+ (sink . errorful)+ NONE+ where+ jsonHeaders_ = biasHeaders headers_ [contentType =: applicationJSON]+----------------------------------------------------------------------------+-- | Sends a POST request with JSON encoded data and expects JSON response.+postJSON'+ :: (FromJSVal error, ToJSON body, FromJSON return)+ => MisoString+ -- ^ url+ -> body+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response return -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+postJSON' url body_ headers_ successful errorful =+ withSink $ \sink -> do+ bodyVal <- toJSVal (encode body_)+ FFI.fetch url "POST" (Just bodyVal) jsonHeaders_+ (handleJSON sink)+ (sink . errorful)+ JSON+ where+ jsonHeaders_ = biasHeaders headers_ [contentType =: applicationJSON, accept =: applicationJSON]+ handleJSON sink resp@Response {..} =+ fmap fromJSON <$> fromJSVal body >>= \case+ Nothing -> do+ err <- fromJSValUnchecked body+ sink $ errorful $ Response+ { body = err+ , errorMessage = Just "Not a valid JSON object"+ , ..+ }+ Just (Success result) ->+ sink $ successful resp { body = result }+ Just (Error msg) -> do+ err <- fromJSValUnchecked body+ sink $ errorful $ Response+ { body = err+ , errorMessage = Just (ms msg)+ , ..+ }+----------------------------------------------------------------------------+-- | Sends a PUT request with JSON encoded data.+putJSON+ :: (FromJSVal error, ToJSON body)+ => MisoString+ -- ^ url+ -> body+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response () -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+putJSON url body_ headers_ successful errorful =+ withSink $ \sink -> do+ bodyVal <- toJSVal (encode body_)+ FFI.fetch url "PUT" (Just bodyVal) jsonHeaders_+ (sink . successful)+ (sink . errorful)+ NONE+ where+ jsonHeaders_ = biasHeaders headers_ [contentType =: applicationJSON]+----------------------------------------------------------------------------+-- | Retrieves text using the Fetch API.+getText+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response MisoString -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+getText url headers_ successful errorful =+ withSink $ \sink ->+ FFI.fetch url "GET" Nothing textHeaders_+ (sink . successful)+ (sink . errorful)+ TEXT -- dmj: expected return type+ where+ textHeaders_ = biasHeaders headers_ [accept =: textPlain]+----------------------------------------------------------------------------+-- | Sends a POST request with text data.+postText+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> MisoString+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response () -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+postText url body_ headers_ successful errorful =+ withSink $ \sink -> do+ bodyVal <- toJSVal (encode body_)+ FFI.fetch url "POST" (Just bodyVal) textHeaders_+ (sink . successful)+ (sink . errorful)+ NONE+ where+ textHeaders_ = biasHeaders headers_ [contentType =: textPlain]+----------------------------------------------------------------------------+-- | Sends a PUT request with text data.+putText+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> MisoString+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response () -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+putText url imageBody headers_ successful errorful =+ withSink $ \sink -> do+ body_ <- toJSVal imageBody+ FFI.fetch url "PUT" (Just body_) textHeaders_+ (sink . successful)+ (sink . errorful)+ NONE+ where+ textHeaders_ = biasHeaders headers_ [contentType =: textPlain]+----------------------------------------------------------------------------+-- | Retrieves a Blob using the Fetch API.+getBlob+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response Blob -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+getBlob url headers_ successful errorful =+ withSink $ \sink ->+ FFI.fetch url "GET" Nothing blobHeaders_+ (sink . successful)+ (sink . errorful)+ BLOB -- dmj: expected return type+ where+ blobHeaders_ = biasHeaders headers_ [accept =: octetStream]+----------------------------------------------------------------------------+-- | Sends a POST request with a Blob.+postBlob+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> Blob+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response () -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+postBlob url body_ headers_ successful errorful =+ withSink $ \sink -> do+ bodyVal <- toJSVal body_+ FFI.fetch url "POST" (Just bodyVal) blobHeaders_+ (sink . successful)+ (sink . errorful)+ NONE+ where+ blobHeaders_ = biasHeaders headers_ [contentType =: octetStream]+----------------------------------------------------------------------------+-- | Sends a PUT request with a Blob.+putBlob+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> Blob+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response () -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+putBlob url imageBody headers_ successful errorful =+ withSink $ \sink -> do+ body_ <- toJSVal imageBody+ FFI.fetch url "PUT" (Just body_) blobHeaders_+ (sink . successful)+ (sink . errorful)+ NONE+ where+ blobHeaders_ = biasHeaders headers_ [contentType =: octetStream]+----------------------------------------------------------------------------+-- | Retrieves FormData using the Fetch API.+getFormData+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response FormData -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+getFormData url headers_ successful errorful =+ withSink $ \sink ->+ FFI.fetch url "GET" Nothing formDataHeaders_+ (sink . successful)+ (sink . errorful)+ FORM_DATA -- dmj: expected return type+ where+ formDataHeaders_ = biasHeaders headers_ [accept =: formData]+----------------------------------------------------------------------------+-- | Sends a POST request with FormData.+postFormData+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> FormData+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response () -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+postFormData url body_ headers_ successful errorful =+ withSink $ \sink -> do+ bodyVal <- toJSVal body_+ FFI.fetch url "POST" (Just bodyVal) formDataHeaders_+ (sink . successful)+ (sink . errorful)+ NONE+ where+ formDataHeaders_ = biasHeaders headers_ [contentType =: formData]+----------------------------------------------------------------------------+-- | Sends a PUT request with FormData.+putFormData+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> FormData+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response () -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+putFormData url imageBody headers_ successful errorful =+ withSink $ \sink -> do+ body_ <- toJSVal imageBody+ FFI.fetch url "PUT" (Just body_) formDataHeaders_+ (sink . successful)+ (sink . errorful)+ NONE+ where+ formDataHeaders_ = biasHeaders headers_ [contentType =: formData]+----------------------------------------------------------------------------+-- | Retrieves an ArrayBuffer using the Fetch API.+getArrayBuffer+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response ArrayBuffer -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+getArrayBuffer url headers_ successful errorful =+ withSink $ \sink ->+ FFI.fetch url "GET" Nothing arrayBufferHeaders_+ (sink . successful)+ (sink . errorful)+ ARRAY_BUFFER -- dmj: expected return type+ where+ arrayBufferHeaders_ = biasHeaders headers_ [accept =: octetStream]+----------------------------------------------------------------------------+-- | Sends a POST request with an ArrayBuffer.+postArrayBuffer+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> ArrayBuffer+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response () -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+postArrayBuffer url body_ headers_ successful errorful =+ withSink $ \sink -> do+ bodyVal <- toJSVal body_+ FFI.fetch url "POST" (Just bodyVal) arrayBufferHeaders_+ (sink . successful)+ (sink . errorful)+ NONE+ where+ arrayBufferHeaders_ = biasHeaders headers_ [contentType =: octetStream]+----------------------------------------------------------------------------+-- | Sends a PUT request with an ArrayBuffer.+putArrayBuffer+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> ArrayBuffer+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response () -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+putArrayBuffer url arrayBuffer_ headers_ successful errorful =+ withSink $ \sink -> do+ body_ <- toJSVal arrayBuffer_+ FFI.fetch url "PUT" (Just body_) arrayBufferHeaders_+ (sink . successful)+ (sink . errorful)+ NONE+ where+ arrayBufferHeaders_ = biasHeaders headers_ [contentType =: octetStream]+----------------------------------------------------------------------------+-- | Retrieves a Uint8Array using the Fetch API.+getUint8Array+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response Uint8Array -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+getUint8Array url headers_ successful errorful =+ withSink $ \sink ->+ FFI.fetch url "GET" Nothing uint8ArrayHeaders_+ (sink . successful)+ (sink . errorful)+ BYTES -- expected return type+ where+ uint8ArrayHeaders_ = biasHeaders headers_ [accept =: octetStream]+----------------------------------------------------------------------------+-- | Sends a POST request with a Uint8Array.+postUint8Array+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> Uint8Array+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response () -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+postUint8Array url body_ headers_ successful errorful =+ withSink $ \sink -> do+ bodyVal <- toJSVal body_+ FFI.fetch url "POST" (Just bodyVal) uint8ArrayHeaders_+ (sink . successful)+ (sink . errorful)+ NONE+ where+ uint8ArrayHeaders_ = biasHeaders headers_ [contentType =: octetStream]+----------------------------------------------------------------------------+-- | Sends a PUT request with a Uint8Array.+putUint8Array+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> Uint8Array+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response () -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+putUint8Array url uint8Array_ headers_ successful errorful =+ withSink $ \sink -> do+ body_ <- toJSVal uint8Array_+ FFI.fetch url "PUT" (Just body_) uint8ArrayHeaders_+ (sink . successful)+ (sink . errorful)+ NONE+ where+ uint8ArrayHeaders_ = biasHeaders headers_ [contentType =: octetStream]+----------------------------------------------------------------------------+-- | Sends a POST request with an 'Image'.+postImage+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> Image+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response () -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+postImage url body_ headers_ successful errorful =+ withSink $ \sink -> do+ bodyVal <- toJSVal body_+ FFI.fetch url "POST" (Just bodyVal) headers_+ (sink . successful)+ (sink . errorful)+ NONE+----------------------------------------------------------------------------+-- | Sends a PUT request with an 'Image'.+putImage+ :: FromJSVal error+ => MisoString+ -- ^ url+ -> Image+ -- ^ Body+ -> [(MisoString, MisoString)]+ -- ^ headers_+ -> (Response () -> action)+ -- ^ successful callback+ -> (Response error -> action)+ -- ^ errorful callback+ -> Effect parent model action+putImage url imageBody headers_ successful errorful =+ withSink $ \sink -> do+ body_ <- toJSVal imageBody+ FFI.fetch url "PUT" (Just body_) headers_+ (sink . successful)+ (sink . errorful)+ NONE+----------------------------------------------------------------------------+-- | Type synonym for request body.+type Body = JSVal+----------------------------------------------------------------------------+-- | Value for specifying "Accept" in an HTTP header+accept :: MisoString+accept = "Accept"+----------------------------------------------------------------------------+-- | Value for specifying "Content-Type" in an HTTP header+contentType :: MisoString+contentType = "Content-Type"+----------------------------------------------------------------------------+-- | Value for specifying "application/json" in an HTTP header+applicationJSON :: MisoString+applicationJSON = "application/json"+----------------------------------------------------------------------------+-- | Value for specifying "text/plain" in an HTTP header+textPlain :: MisoString+textPlain = "text/plain"+----------------------------------------------------------------------------+-- | Value for specifying "application/octet-stream" in an HTTP header+octetStream :: MisoString+octetStream = "application/octet-stream"+----------------------------------------------------------------------------+-- | Value for specifying "multipart/form-data" in an HTTP header+formData :: MisoString+formData = "multipart/form-data"+----------------------------------------------------------------------------+-- | Helper function for the union of two header Map+biasHeaders :: Ord k => [(k, a)] -> [(k, a)] -> [(k, a)]+biasHeaders userDefined contentSpecific+ = M.toList+ $ M.fromList userDefined <> M.fromList contentSpecific+----------------------------------------------------------------------------
src/Miso/Html.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Miso.Html--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental@@ -11,30 +11,34 @@ -- -- @ -- import Miso+-- import Miso.String ----- data IntAction = Add | Subtract+-- data Action = Add | Subtract ----- intView :: Int -> View IntAction--- intView n = div_ [ class_ "main" ] [--- btn_ [ onClick Add ] [ text_ "+" ]--- , text_ $ pack (show n)--- , btn_ [ onClick Subtract ] [ text_ "-" ]+-- view_ :: Int -> View Int Action+-- view_ n = div_+-- [ class_ "main" ]+-- [ button_ [ onClick Add ] [ text_ "+" ]+-- , text_ (ms n)+-- , button_ [ onClick Subtract ] [ text_ "-" ] -- ] -- @ ----- More information on how to use `miso` is available on GitHub+-- More information on how to use @miso@ is available on GitHub. -- -- <http://github.com/dmjio/miso> -- ---------------------------------------------------------------------------- module Miso.Html- ( module Miso.Html.Element+ ( -- ** Elements+ module Miso.Html.Element+ -- ** Events , module Miso.Html.Event- , module Miso.Html.Types- , module Miso.Html.Property+ -- ** Render+ , module Miso.Html.Render ) where--import Miso.Html.Element hiding (style_)+-----------------------------------------------------------------------------+import Miso.Html.Element import Miso.Html.Event-import Miso.Html.Types hiding (textRaw)-import Miso.Html.Property hiding (form_)+import Miso.Html.Render+-----------------------------------------------------------------------------
src/Miso/Html/Element.hs view
@@ -1,508 +1,571 @@+----------------------------------------------------------------------------- {-# LANGUAGE OverloadedStrings #-} ----------------------------------------------------------------------------- -- | -- Module : Miso.Html.Element--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable+--+-- Predefined list of HTML elements+-- ---------------------------------------------------------------------------- module Miso.Html.Element- ( -- * Construct an Element+ ( -- ** Smart constructors nodeHtml- , nodeHtmlKeyed- -- * Headers+ -- ** Document metadata+ , html_+ , doctype_+ , base_+ , head_+ , link_+ , meta_+ , style_+ , title_+ -- ** Sectioning root+ , body_+ -- ** Content sectioning+ , address_+ , article_+ , aside_+ , footer_+ , header_ , h1_ , h2_ , h3_ , h4_ , h5_ , h6_- -- * Grouping Content+ , hgroup_+ , main_+ , nav_+ , section_+ , search_+ -- ** Text content+ , blockquote_+ , dd_ , div_- , p_+ , dl_+ , dt_+ , figcaption_+ , figure_ , hr_+ , li_+ , menu_+ , ol_+ , p_ , pre_- , blockquote_- -- * Text+ , ul_+ -- ** Inline text semantics+ , a_+ , abbr_+ , b_+ , bdi_+ , bdo_+ , br_+ , cite_ , code_+ , data_+ , dfn_ , em_+ , i_+ , kbd_+ , mark_+ , q_+ , rp_+ , rt_+ , ruby_+ , s_+ , samp_+ , small_ , span_- , a_ , strong_- , i_- , b_- , u_ , sub_ , sup_- , br_- -- * Lists- , ol_- , ul_- , li_- , liKeyed_- , dl_- , dt_- , dd_- -- * Embedded Content+ , time_+ , u_+ , var_+ , wbr_+ -- ** Image and multimedia+ , area_+ , audio_ , img_+ , map_+ , track_+ , video_+ -- ** Embedded content+ , embed_+ , fencedframe_ , iframe_+ , object_+ , picture_+ , source_+ -- ** Scripting , canvas_- , math_+ , noscript_ , script_- , link_- , Miso.Html.Element.style_- -- * Inputs- , select_- , option_- , textarea_- , form_- , input_- , button_- -- * Sections- , section_- , header_- , footer_- , nav_- , article_- , aside_- , address_- , main_- , body_- -- * Figures- , figure_- , figcaption_- -- * Tables- , table_+ -- ** Demarcating edits+ , del_+ , ins_+ -- ** Table content , caption_- , colgroup_ , col_+ , colgroup_+ , table_ , tbody_- , thead_- , tfoot_- , tr_- , trKeyed_ , td_+ , tfoot_ , th_- -- * Less common elements- , label_+ , thead_+ , tr_+ -- ** Forms+ , button_+ , datalist_ , fieldset_+ , form_+ , input_+ , label_ , legend_- , datalist_+ , meter_ , optgroup_- , keygen_+ , option_ , output_ , progress_- , meter_- , center_- -- * Audio and Video- , audio_- , video_- , source_- , track_- -- * Embedded objects- , embed_- , object_- , param_- -- * Text edits- , ins_- , del_- -- * Semantic text- , small_- , cite_- , dfn_- , abbr_- , time_- , var_- , samp_- , kbd_- , q_- , s_- -- * Less common tags- , mark_- , ruby_- , rt_- , rp_- , bdi_- , bdo_- , wbr_- -- * Interactive elements+ , select_+ , textarea_+ -- ** Interactive elements , details_+ , dialog_ , summary_- , menuitem_- , menu_+ -- ** Web components+ , slot_+ , template_+ -- * SVG+ , svg_ ) where--import Miso.Html.Types-import Miso.String (MisoString)---- | Used to construct `VNode`'s in `View`-nodeHtml :: MisoString -> [Attribute action] -> [View action] -> View action-nodeHtml = flip (node HTML) Nothing---- | Construct a node with a `Key`-nodeHtmlKeyed :: MisoString -> Key -> [Attribute action] -> [View action] -> View action-nodeHtmlKeyed name = node HTML name . pure---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div-div_ :: [Attribute action] -> [View action] -> View action-div_ = nodeHtml "div"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table-table_ :: [Attribute action] -> [View action] -> View action-table_ = nodeHtml "table"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/thead-thead_ :: [Attribute action] -> [View action] -> View action-thead_ = nodeHtml "thead"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tbody-tbody_ :: [Attribute action] -> [View action] -> View action-tbody_ = nodeHtml "tbody"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tr-tr_ :: [Attribute action] -> [View action] -> View action-tr_ = nodeHtml "tr"---- | Contains `Key`, inteded to be used for child replacement patch------ <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tr>--trKeyed_ :: Key -> [Attribute action] -> [View action] -> View action-trKeyed_ = node HTML "tr" . pure---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/th-th_ :: [Attribute action] -> [View action] -> View action-th_ = nodeHtml "th"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td-td_ :: [Attribute action] -> [View action] -> View action-td_ = nodeHtml "td"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tfoot-tfoot_ :: [Attribute action] -> [View action] -> View action-tfoot_ = nodeHtml "tfoot"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/section-section_ :: [Attribute action] -> [View action] -> View action-section_ = nodeHtml "section"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/header-header_ :: [Attribute action] -> [View action] -> View action-header_ = nodeHtml "header"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/footer-footer_ :: [Attribute action] -> [View action] -> View action-footer_ = nodeHtml "footer"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button-button_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+import Miso.Types+-----------------------------------------------------------------------------+import Miso.Svg.Element (svg_)+-----------------------------------------------------------------------------+-- | Low-level helper used to construct 'HTML' 'node' in 'Miso.Types.View'.+-- Almost all functions in this module, like 'div_', 'table_' etc. are defined in terms of it.+nodeHtml :: MisoString -> [Attribute action] -> [View model action] -> View model action+nodeHtml nodeName = node HTML nodeName+-----------------------------------------------------------------------------+-- | [\<div\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/div)+div_ :: [Attribute action] -> [View model action] -> View model action+div_ = nodeHtml "div"+-----------------------------------------------------------------------------+-- | [\<table\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/table)+table_ :: [Attribute action] -> [View model action] -> View model action+table_ = nodeHtml "table"+-----------------------------------------------------------------------------+-- | [\<thead\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/thead)+thead_ :: [Attribute action] -> [View model action] -> View model action+thead_ = nodeHtml "thead"+-----------------------------------------------------------------------------+-- | [\<tbody\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/tbody)+tbody_ :: [Attribute action] -> [View model action] -> View model action+tbody_ = nodeHtml "tbody"+-----------------------------------------------------------------------------+-- | [\<tr\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/tr)+tr_ :: [Attribute action] -> [View model action] -> View model action+tr_ = nodeHtml "tr"+-----------------------------------------------------------------------------+-- | [\<th\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/th)+th_ :: [Attribute action] -> [View model action] -> View model action+th_ = nodeHtml "th"+-----------------------------------------------------------------------------+-- | [\<td\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/td)+td_ :: [Attribute action] -> [View model action] -> View model action+td_ = nodeHtml "td"+-----------------------------------------------------------------------------+-- | [\<tfoot\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/tfoot)+tfoot_ :: [Attribute action] -> [View model action] -> View model action+tfoot_ = nodeHtml "tfoot"+-----------------------------------------------------------------------------+-- | [\<section\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/section)+section_ :: [Attribute action] -> [View model action] -> View model action+section_ = nodeHtml "section"+-----------------------------------------------------------------------------+-- | [\<header\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/header)+header_ :: [Attribute action] -> [View model action] -> View model action+header_ = nodeHtml "header"+-----------------------------------------------------------------------------+-- | [\<footer\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/footer)+footer_ :: [Attribute action] -> [View model action] -> View model action+footer_ = nodeHtml "footer"+-----------------------------------------------------------------------------+-- | [\<button\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/button)+button_ :: [Attribute action] -> [View model action] -> View model action button_ = nodeHtml "button"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form-form_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<form\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form)+--+-- For usage in a real-world application with the @onSubmit@ event.+--+-- > view :: Model -> View model action+-- > view model = form_ [ onSubmit NoOp ] [ input [ type_ "submit" ] ]+--+-- Note: @onSubmit@ will use @preventDefault = True@. This will keep+-- the form from submitting to the server.+--+form_ :: [Attribute action] -> [View model action] -> View model action form_ = nodeHtml "form"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/p-p_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<p\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/p)+p_ :: [Attribute action] -> [View model action] -> View model action p_ = nodeHtml "p"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/s-s_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<s\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/s)+s_ :: [Attribute action] -> [View model action] -> View model action s_ = nodeHtml "s"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul-ul_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<ul\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/ul)+ul_ :: [Attribute action] -> [View model action] -> View model action ul_ = nodeHtml "ul"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/span-span_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<span\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/span)+span_ :: [Attribute action] -> [View model action] -> View model action span_ = nodeHtml "span"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/strong-strong_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<strong\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/strong)+strong_ :: [Attribute action] -> [View model action] -> View model action strong_ = nodeHtml "strong"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/li-li_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<li\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/li)+li_ :: [Attribute action] -> [View model action] -> View model action li_ = nodeHtml "li"---- | Contains `Key`, inteded to be used for child replacement patch------ <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/li>----liKeyed_ :: Key -> [Attribute action] -> [View action] -> View action-liKeyed_ = node HTML "li" . pure---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h1-h1_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<h1\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements)+h1_ :: [Attribute action] -> [View model action] -> View model action h1_ = nodeHtml "h1"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h2-h2_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<h2\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements)+h2_ :: [Attribute action] -> [View model action] -> View model action h2_ = nodeHtml "h2"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h3-h3_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<h3\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements)+h3_ :: [Attribute action] -> [View model action] -> View model action h3_ = nodeHtml "h3"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h4-h4_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<h4\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements)+h4_ :: [Attribute action] -> [View model action] -> View model action h4_ = nodeHtml "h4"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h5-h5_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<h5\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements)+h5_ :: [Attribute action] -> [View model action] -> View model action h5_ = nodeHtml "h5"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h6-h6_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<h6\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/Heading_Elements)+h6_ :: [Attribute action] -> [View model action] -> View model action h6_ = nodeHtml "h6"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/hr-hr_ :: [Attribute action] -> View action+-----------------------------------------------------------------------------+-- | [\<hr\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/hr)+hr_ :: [Attribute action] -> View model action hr_ = flip (nodeHtml "hr") []---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/pre-pre_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<pre\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/pre)+pre_ :: [Attribute action] -> [View model action] -> View model action pre_ = nodeHtml "pre"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input-input_ :: [Attribute action] -> View action+-----------------------------------------------------------------------------+-- | [\<input\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input)+input_ :: [Attribute action] -> View model action input_ = flip (nodeHtml "input") []---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label-label_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<label\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/label)+label_ :: [Attribute action] -> [View model action] -> View model action label_ = nodeHtml "label"---- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a-a_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<a\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a)+a_ :: [Attribute action] -> [View model action] -> View model action a_ = nodeHtml "a"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/mark-mark_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<mark\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/mark)+mark_ :: [Attribute action] -> [View model action] -> View model action mark_ = nodeHtml "mark"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ruby-ruby_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<ruby\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/ruby)+ruby_ :: [Attribute action] -> [View model action] -> View model action ruby_ = nodeHtml "ruby"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rt-rt_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<rt\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/rt)+rt_ :: [Attribute action] -> [View model action] -> View model action rt_ = nodeHtml "rt"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rp-rp_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<rp\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/rp)+rp_ :: [Attribute action] -> [View model action] -> View model action rp_ = nodeHtml "rp"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdi-bdi_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<bdi\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/bdi)+bdi_ :: [Attribute action] -> [View model action] -> View model action bdi_ = nodeHtml "bdi"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdo-bdo_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<bdo\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/bdo)+bdo_ :: [Attribute action] -> [View model action] -> View model action bdo_ = nodeHtml "bdo"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/wbr-wbr_ :: [Attribute action] -> View action+-----------------------------------------------------------------------------+-- | [\<wbr\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/wbr)+wbr_ :: [Attribute action] -> View model action wbr_ = flip (nodeHtml "wbr") []--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details-details_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<details\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/details)+details_ :: [Attribute action] -> [View model action] -> View model action details_ = nodeHtml "details"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary-summary_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<summary\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/summary)+summary_ :: [Attribute action] -> [View model action] -> View model action summary_ = nodeHtml "summary"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem-menuitem_ :: [Attribute action] -> [View action] -> View action-menuitem_ = nodeHtml "menuitem"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menu-menu_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<menu\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/menu)+menu_ :: [Attribute action] -> [View model action] -> View model action menu_ = nodeHtml "menu"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset-fieldset_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<fieldset\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/fieldset)+fieldset_ :: [Attribute action] -> [View model action] -> View model action fieldset_ = nodeHtml "fieldset"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/legend-legend_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<legend\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/legend)+legend_ :: [Attribute action] -> [View model action] -> View model action legend_ = nodeHtml "legend"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist-datalist_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<datalist\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/datalist)+datalist_ :: [Attribute action] -> [View model action] -> View model action datalist_ = nodeHtml "datalist"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup-optgroup_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<optgroup\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/optgroup)+optgroup_ :: [Attribute action] -> [View model action] -> View model action optgroup_ = nodeHtml "optgroup"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/keygen-keygen_ :: [Attribute action] -> [View action] -> View action-keygen_ = nodeHtml "keygen"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/output-output_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<output\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/output)+output_ :: [Attribute action] -> [View model action] -> View model action output_ = nodeHtml "output"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress-progress_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<progress\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/progress)+progress_ :: [Attribute action] -> [View model action] -> View model action progress_ = nodeHtml "progress"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meter-meter_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<meter\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meter)+meter_ :: [Attribute action] -> [View model action] -> View model action meter_ = nodeHtml "meter"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/center-center_ :: [Attribute action] -> [View action] -> View action-center_ = nodeHtml "center"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio-audio_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<audio\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/audio)+audio_ :: [Attribute action] -> [View model action] -> View model action audio_ = nodeHtml "audio"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video-video_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<video\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/video)+video_ :: [Attribute action] -> [View model action] -> View model action video_ = nodeHtml "video"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source-source_ :: [Attribute action] -> View action+-----------------------------------------------------------------------------+-- | [\<source\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/source)+source_ :: [Attribute action] -> View model action source_ = flip (nodeHtml "source") []--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/track-track_ :: [Attribute action] -> View action+-----------------------------------------------------------------------------+-- | [\<track\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/track)+track_ :: [Attribute action] -> View model action track_ = flip (nodeHtml "track") []--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/embed-embed_ :: [Attribute action] -> View action+-----------------------------------------------------------------------------+-- | [\<embed\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/embed)+embed_ :: [Attribute action] -> View model action embed_ = flip (nodeHtml "embed") []--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object-object_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<object\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/object)+object_ :: [Attribute action] -> [View model action] -> View model action object_ = nodeHtml "object"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/param-param_ :: [Attribute action] -> View action-param_ = flip (nodeHtml "param") []--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ins-ins_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<ins\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/ins)+ins_ :: [Attribute action] -> [View model action] -> View model action ins_ = nodeHtml "ins"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/del-del_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<del\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/del)+del_ :: [Attribute action] -> [View model action] -> View model action del_ = nodeHtml "del"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/small-small_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<small\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/small)+small_ :: [Attribute action] -> [View model action] -> View model action small_ = nodeHtml "small"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/cite-cite_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<cite\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/cite)+cite_ :: [Attribute action] -> [View model action] -> View model action cite_ = nodeHtml "cite"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dfn-dfn_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<dfn\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dfn)+dfn_ :: [Attribute action] -> [View model action] -> View model action dfn_ = nodeHtml "dfn"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/abbr-abbr_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<abbr\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/abbr)+abbr_ :: [Attribute action] -> [View model action] -> View model action abbr_ = nodeHtml "abbr"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time-time_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<time\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/time)+time_ :: [Attribute action] -> [View model action] -> View model action time_ = nodeHtml "time"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/var-var_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<var\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/var)+var_ :: [Attribute action] -> [View model action] -> View model action var_ = nodeHtml "var"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/samp-samp_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<samp\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/samp)+samp_ :: [Attribute action] -> [View model action] -> View model action samp_ = nodeHtml "samp"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd-kbd_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<kbd\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/kbd)+kbd_ :: [Attribute action] -> [View model action] -> View model action kbd_ = nodeHtml "kbd"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/caption-caption_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<caption\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/caption)+caption_ :: [Attribute action] -> [View model action] -> View model action caption_ = nodeHtml "caption"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/colgroup-colgroup_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<colgroup\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/colgroup)+colgroup_ :: [Attribute action] -> [View model action] -> View model action colgroup_ = nodeHtml "colgroup"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/col-col_ :: [Attribute action] -> View action+-----------------------------------------------------------------------------+-- | [\<col\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/col)+col_ :: [Attribute action] -> View model action col_ = flip (nodeHtml "col") []--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/nav-nav_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<nav\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/nav)+nav_ :: [Attribute action] -> [View model action] -> View model action nav_ = nodeHtml "nav"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/article-article_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<article\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/article)+article_ :: [Attribute action] -> [View model action] -> View model action article_ = nodeHtml "article"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/aside-aside_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<aside\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/aside)+aside_ :: [Attribute action] -> [View model action] -> View model action aside_ = nodeHtml "aside"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/address-address_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<address\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/address)+address_ :: [Attribute action] -> [View model action] -> View model action address_ = nodeHtml "address"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/main-main_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<main\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/main)+main_ :: [Attribute action] -> [View model action] -> View model action main_ = nodeHtml "main"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/body-body_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<body\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/body)+body_ :: [Attribute action] -> [View model action] -> View model action body_ = nodeHtml "body"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figure-figure_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<figure\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/figure)+figure_ :: [Attribute action] -> [View model action] -> View model action figure_ = nodeHtml "figure"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figcaption-figcaption_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<figcaption\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/figcaption)+figcaption_ :: [Attribute action] -> [View model action] -> View model action figcaption_ = nodeHtml "figcaption"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl-dl_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<dl\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dl)+dl_ :: [Attribute action] -> [View model action] -> View model action dl_ = nodeHtml "dl"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dt-dt_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<dt\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dt)+dt_ :: [Attribute action] -> [View model action] -> View model action dt_ = nodeHtml "dt"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dd-dd_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<dd\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dd)+dd_ :: [Attribute action] -> [View model action] -> View model action dd_ = nodeHtml "dd"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img-img_ :: [Attribute action] -> View action+-----------------------------------------------------------------------------+-- | [\<img\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img)+img_ :: [Attribute action] -> View model action img_ = flip (nodeHtml "img") []--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe-iframe_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<iframe\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/iframe)+iframe_ :: [Attribute action] -> [View model action] -> View model action iframe_ = nodeHtml "iframe"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas-canvas_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<canvas\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/canvas)+--+-- Note this just renders a canvas element.+-- See also 'Miso.Canvas.canvas_' which supports canvas drawing DSL.+canvas_ :: [Attribute action] -> [View model action] -> View model action canvas_ = nodeHtml "canvas"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/math-math_ :: [Attribute action] -> [View action] -> View action-math_ = nodeHtml "math"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select-select_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<select\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/select)+select_ :: [Attribute action] -> [View model action] -> View model action select_ = nodeHtml "select"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option-option_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<option\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/option)+option_ :: [Attribute action] -> [View model action] -> View model action option_ = nodeHtml "option"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea-textarea_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<textarea\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/textarea)+textarea_ :: [Attribute action] -> [View model action] -> View model action textarea_ = nodeHtml "textarea"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sub-sub_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<sub\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/sub)+sub_ :: [Attribute action] -> [View model action] -> View model action sub_ = nodeHtml "sub"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sup-sup_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<sup\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/sup)+sup_ :: [Attribute action] -> [View model action] -> View model action sup_ = nodeHtml "sup"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/br-br_ :: [Attribute action] -> View action+-----------------------------------------------------------------------------+-- | [\<br\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/br)+br_ :: [Attribute action] -> View model action br_ = flip (nodeHtml "br") []--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol-ol_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<ol\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/ol)+ol_ :: [Attribute action] -> [View model action] -> View model action ol_ = nodeHtml "ol"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote-blockquote_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<blockquote\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/blockquote)+blockquote_ :: [Attribute action] -> [View model action] -> View model action blockquote_ = nodeHtml "blockquote"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/code-code_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<code\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/code)+code_ :: [Attribute action] -> [View model action] -> View model action code_ = nodeHtml "code"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/em-em_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<em\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/em)+em_ :: [Attribute action] -> [View model action] -> View model action em_ = nodeHtml "em"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/i-i_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<i\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/i)+i_ :: [Attribute action] -> [View model action] -> View model action i_ = nodeHtml "i"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/b-b_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<b\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/b)+b_ :: [Attribute action] -> [View model action] -> View model action b_ = nodeHtml "b"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/u-u_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<u\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/u)+u_ :: [Attribute action] -> [View model action] -> View model action u_ = nodeHtml "u"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q-q_ :: [Attribute action] -> [View action] -> View action+-----------------------------------------------------------------------------+-- | [\<q\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/q)+q_ :: [Attribute action] -> [View model action] -> View model action q_ = nodeHtml "q"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link-link_ :: [Attribute action] -> View action+-----------------------------------------------------------------------------+-- | [\<link\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/link)+link_ :: [Attribute action] -> View model action link_ = flip (nodeHtml "link") []--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style+-----------------------------------------------------------------------------+-- | [\<style\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/style) -- -- This takes the raw text to be put in the style tag. -- -- That means that if any part of the text is not trusted there's--- a potential CSS injection. Read more at--- https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client_Side_Testing/05-Testing_for_CSS_Injection+-- a potential [CSS injection](https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/11-Client-side_Testing/05-Testing_for_CSS_Injection). -- -- You can also easily shoot yourself in the foot with something like: ----- @'style_' [] "\</style\>"@-style_ :: [Attribute action] -> MisoString -> View action-style_ attrs rawText = node HTML "style" Nothing attrs [textRaw rawText]--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script+-- @+-- style_ [] "\</style\>"+-- @ --+-- You can use 'Miso.CSS.style_' as a safer anternative.+style_ :: [Attribute action] -> MisoString -> View model action+style_ attrs rawText = node HTML "style" attrs [text rawText]+-----------------------------------------------------------------------------+-- | [\<script\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script)+-- -- This takes the raw text to be put in the script tag. -- -- That means that if any part of the text is not trusted there's@@ -512,5 +575,100 @@ -- You can also easily shoot yourself in the foot with something like: -- -- @'script_' [] "\</script\>"@-script_ :: [Attribute action] -> MisoString -> View action-script_ attrs rawText = node HTML "script" Nothing attrs [textRaw rawText]+script_ :: [Attribute action] -> MisoString -> View model action+script_ attrs rawText = node HTML "script" attrs [textRaw rawText]+-----------------------------------------------------------------------------+-- | [\<doctype\>](https://developer.mozilla.org/en-US/docs/Glossary/Doctype)+doctype_ :: View model action+doctype_ = nodeHtml "doctype" [] []+-----------------------------------------------------------------------------+-- | [\<html\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/html)+html_ :: [Attribute action] -> [View model action] -> View model action+html_ = nodeHtml "html"+-----------------------------------------------------------------------------+-- | [\<head\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/head)+head_ :: [Attribute action] -> [View model action] -> View model action+head_ = nodeHtml "head"+-----------------------------------------------------------------------------+-- | [\<meta\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta)+meta_ :: [Attribute action] -> View model action+meta_ = flip (nodeHtml "meta") []+-----------------------------------------------------------------------------+-- | [\<area\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/area)+--+-- @since 1.9.0.0+area_ :: [Attribute action] -> [View model action] -> View model action+area_ = nodeHtml "area"+-----------------------------------------------------------------------------+-- | [\<base\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/base)+--+-- @since 1.9.0.0+base_ :: [Attribute action] -> [View model action] -> View model action+base_ = nodeHtml "base"+-----------------------------------------------------------------------------+-- | [\<data\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/data)+--+-- @since 1.9.0.0+data_ :: [Attribute action] -> [View model action] -> View model action+data_ = nodeHtml "data"+-----------------------------------------------------------------------------+-- | [\<dialog\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/dialog)+--+-- @since 1.9.0.0+dialog_ :: [Attribute action] -> [View model action] -> View model action+dialog_ = nodeHtml "dialog"+-----------------------------------------------------------------------------+-- | [\<fencedframe\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/fencedframe)+--+-- @since 1.9.0.0+fencedframe_ :: [Attribute action] -> [View model action] -> View model action+fencedframe_ = nodeHtml "fencedframe"+-----------------------------------------------------------------------------+-- | [\<hgroup\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/hgroup)+--+-- @since 1.9.0.0+hgroup_ :: [Attribute action] -> [View model action] -> View model action+hgroup_ = nodeHtml "hgroup"+-----------------------------------------------------------------------------+-- | [\<map\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/map)+--+-- @since 1.9.0.0+map_ :: [Attribute action] -> [View model action] -> View model action+map_ = nodeHtml "map"+-----------------------------------------------------------------------------+-- | [\<noscript\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/noscript)+--+-- @since 1.9.0.0+noscript_ :: [Attribute action] -> [View model action] -> View model action+noscript_ = nodeHtml "noscript"+-----------------------------------------------------------------------------+-- | [\<picture\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/picture)+--+-- @since 1.9.0.0+picture_ :: [Attribute action] -> [View model action] -> View model action+picture_ = nodeHtml "picture"+-----------------------------------------------------------------------------+-- | [\<search\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/search)+--+-- @since 1.9.0.0+search_ :: [Attribute action] -> [View model action] -> View model action+search_ = nodeHtml "search"+-----------------------------------------------------------------------------+-- | [\<slot\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/slot)+--+-- @since 1.9.0.0+slot_ :: [Attribute action] -> [View model action] -> View model action+slot_ = nodeHtml "slot"+-----------------------------------------------------------------------------+-- | [\<template\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/template)+--+-- @since 1.9.0.0+template_ :: [Attribute action] -> [View model action] -> View model action+template_ = nodeHtml "template"+-----------------------------------------------------------------------------+-- | [\<title\>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/title)+--+-- @since 1.9.0.0+title_ :: [Attribute action] -> [View model action] -> View model action+title_ = nodeHtml "title"+-----------------------------------------------------------------------------
src/Miso/Html/Event.hs view
@@ -1,17 +1,9 @@-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE TypeFamilies #-} -----------------------------------------------------------------------------+{-# LANGUAGE OverloadedStrings #-}+----------------------------------------------------------------------------- -- | -- Module : Miso.Html.Event--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental@@ -19,151 +11,588 @@ -- ---------------------------------------------------------------------------- module Miso.Html.Event- ( -- * Custom event handlers- on- , onWithOptions- , Options (..)- , defaultOptions- -- * Mouse events- , onClick+ ( -- *** Mouse+ onClick+ , onClickPrevent+ , onClickCapture+ , onClickWith+ , onClickWithOptions , onDoubleClick+ , onDoubleClickWith+ , onDoubleClickWithOptions , onMouseDown , onMouseUp , onMouseEnter , onMouseLeave , onMouseOver , onMouseOut- -- * Keyboard events+ , onContextMenuWithOptions+ -- *** Keyboard , onKeyDown , onKeyDownWithInfo , onKeyPress , onKeyUp- -- * Form events+ , onEnter+ -- *** Form , onInput , onChange+ , onChangeWith , onChecked , onSubmit- -- * Focus events+ -- *** Focus , onBlur , onFocus- -- * Drag events+ -- *** Drag , onDrag+ , onDragWithOptions , onDragLeave+ , onDragLeaveWithOptions , onDragEnter+ , onDragEnterWithOptions , onDragEnd+ , onDragEndWithOptions , onDragStart+ , onDragStartWithOptions , onDragOver- -- * Drop events+ , onDragOverWithOptions+ -- *** Drop , onDrop+ , onDropWithOptions+ -- *** Select+ , onSelect+ -- *** Pointer+ , onPointerDown+ , onPointerUp+ , onPointerEnter+ , onPointerLeave+ , onPointerOver+ , onPointerOut+ , onPointerCancel+ , onPointerMove+ -- *** Media+ , onAbort+ , onAbortWith+ , onCanPlay+ , onCanPlayWith+ , onCanPlayThrough+ , onCanPlayThroughWith+ , onDurationChange+ , onDurationChangeWith+ , onEmptied+ , onEmptiedWith+ , onEnded+ , onEndedWith+ , onError+ , onErrorWith+ , onLoad+ , onUnload+ , onLoadedData+ , onLoadedDataWith+ , onLoadedMetadata+ , onLoadedMetadataWith+ , onLoadStart+ , onLoadStartWith+ , onPause+ , onPauseWith+ , onPlay+ , onPlayWith+ , onPlaying+ , onPlayingWith+ , onProgress+ , onProgressWith+ , onRateChange+ , onRateChangeWith+ , onSeeked+ , onSeekedWith+ , onSeeking+ , onSeekingWith+ , onStalled+ , onStalledWith+ , onSuspend+ , onSuspendWith+ , onTimeUpdate+ , onTimeUpdateWith+ , onVolumeChange+ , onVolumeChangeWith+ , onWaiting+ , onWaitingWith+ -- *** Touch+ , onTouchStart+ , onTouchStartWithOptions+ , onTouchEnd+ , onTouchEndWithOptions+ , onTouchMove+ , onTouchMoveWithOptions+ , onTouchCancel+ , onTouchCancelWithOptions ) where--import Miso.Html.Types ( Attribute, on, onWithOptions )-import Miso.Event-import Miso.String (MisoString)---- | `blur` event defined with custom options+-----------------------------------------------------------------------------+import Data.Bool (bool)+-----------------------------------------------------------------------------+import Miso.Event+import Miso.Media (Media(..))+import Miso.Types (Attribute, DOMRef)+import Miso.String (MisoString)+-----------------------------------------------------------------------------+-- | blur event defined with custom options -- -- <https://developer.mozilla.org/en-US/docs/Web/Events/blur> -- onBlur :: action -> Attribute action-onBlur action = on "blur" emptyDecoder $ \() -> action-+onBlur action = on "blur" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/change onChecked :: (Checked -> action) -> Attribute action-onChecked = on "change" checkedDecoder-+onChecked f = on "change" checkedDecoder (\action _ -> f action)+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/contextmenu+--+-- This can be used to disable right-click context menu from appearing+--+-- @+-- div_ [ onContextMenuWithOptions NoOp defaultOptions { preventDefault = False } ] [ ]+-- @+--+-- @since 1.9.0.0+onContextMenuWithOptions :: Options -> action -> Attribute action+onContextMenuWithOptions opts action =+ onWithOptions BUBBLE opts "contextmenu" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/click onClick :: action -> Attribute action-onClick action = on "click" emptyDecoder $ \() -> action-+onClick action = on "click" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/click+onClickCapture :: action -> Attribute action+onClickCapture action = onCapture "click" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/click+-- Like 'onClick', but passes the DOM reference along (akin to @getElementById@).+onClickWith :: (DOMRef -> action) -> Attribute action+onClickWith action = on "click" emptyDecoder $ \() domRef -> action domRef+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/click+onClickWithOptions :: Options -> action -> Attribute action+onClickWithOptions options action = onWithOptions BUBBLE options "click" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/click+onClickPrevent :: action -> Attribute action+onClickPrevent = onClickWithOptions preventDefault+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/focus onFocus :: action -> Attribute action-onFocus action = on "focus" emptyDecoder $ \() -> action-+onFocus action = on "focus" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/dblclick onDoubleClick :: action -> Attribute action-onDoubleClick action = on "dblclick" emptyDecoder $ \() -> action-+onDoubleClick action = on "dblclick" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/dblclick+onDoubleClickWith :: (DOMRef -> action) -> Attribute action+onDoubleClickWith f = on "dblclick" emptyDecoder $ \() domRef -> f domRef+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/dblclick+onDoubleClickWithOptions :: Options -> action -> Attribute action+onDoubleClickWithOptions options action =+ onWithOptions BUBBLE options "dblclick" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/input onInput :: (MisoString -> action) -> Attribute action-onInput = on "input" valueDecoder-+onInput f = on "input" valueDecoder (\action _ -> f action)+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/change onChange :: (MisoString -> action) -> Attribute action-onChange = on "change" valueDecoder-+onChange f = on "change" valueDecoder (\action _ -> f action)+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/change+onChangeWith :: (MisoString -> DOMRef -> action) -> Attribute action+onChangeWith = on "change" valueDecoder+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/select+onSelect :: (MisoString -> action) -> Attribute action+onSelect f = on "select" valueDecoder (\action _ -> f action)+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/keydown onKeyDownWithInfo :: (KeyInfo -> action) -> Attribute action-onKeyDownWithInfo = on "keydown" keyInfoDecoder-+onKeyDownWithInfo f = on "keydown" keyInfoDecoder (\action _ -> f action)+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/keydown onKeyDown :: (KeyCode -> action) -> Attribute action-onKeyDown = on "keydown" keycodeDecoder-+onKeyDown f = on "keydown" keycodeDecoder (\action _ -> f action)+-----------------------------------------------------------------------------+-- | 'onEnter'+--+-- A convenience function for processing the @Enter@ key.+--+-- @+--+-- data Action = NoOp | OnEnter+--+-- type Model = Int+--+-- view :: Model -> View model Action+-- view entryId = input_ [ onEnter NoOp OnEnter ]+-- @+--+-- @since 1.9.0.0+onEnter+ :: action+ -- ^ The action to call when the keydown *is not* 13 (typically @NoOp@ or @Id@)+ -> action+ -- ^ The action to call when keydown *is* 13.+ -> Attribute action+onEnter nothing action = onKeyDown $ bool nothing action . (==13)+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/keypress onKeyPress :: (KeyCode -> action) -> Attribute action-onKeyPress = on "keypress" keycodeDecoder-+onKeyPress f = on "keypress" keycodeDecoder (\action _ -> f action)+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/keyup onKeyUp :: (KeyCode -> action) -> Attribute action-onKeyUp = on "keyup" keycodeDecoder-+onKeyUp f = on "keyup" keycodeDecoder (\action _ -> f action)+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/mouseup onMouseUp :: action -> Attribute action-onMouseUp action = on "mouseup" emptyDecoder $ \() -> action-+onMouseUp action = on "mouseup" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/mousedown onMouseDown :: action -> Attribute action-onMouseDown action = on "mousedown" emptyDecoder $ \() -> action-+onMouseDown action = on "mousedown" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/mouseenter onMouseEnter :: action -> Attribute action-onMouseEnter action = on "mouseenter" emptyDecoder $ \() -> action-+onMouseEnter action = on "mouseenter" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/mouseleave onMouseLeave :: action -> Attribute action-onMouseLeave action = on "mouseleave" emptyDecoder $ \() -> action-+onMouseLeave action = on "mouseleave" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/mouseover onMouseOver :: action -> Attribute action-onMouseOver action = on "mouseover" emptyDecoder $ \() -> action-+onMouseOver action = on "mouseover" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/mouseout onMouseOut :: action -> Attribute action-onMouseOut action = on "mouseout" emptyDecoder $ \() -> action-+onMouseOut action = on "mouseout" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/dragstart onDragStart :: action -> Attribute action-onDragStart action = on "dragstart" emptyDecoder $ \() -> action-+onDragStart action = on "dragstart" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/dragstart+onDragStartWithOptions :: Options -> action -> Attribute action+onDragStartWithOptions options action =+ onWithOptions BUBBLE options "dragstart" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/dragover onDragOver :: action -> Attribute action-onDragOver action = on "dragover" emptyDecoder $ \() -> action-+onDragOver action = on "dragover" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/dragover+onDragOverWithOptions :: Options -> action -> Attribute action+onDragOverWithOptions options action =+ onWithOptions BUBBLE options "dragover" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/dragend onDragEnd :: action -> Attribute action-onDragEnd action = on "dragend" emptyDecoder $ \() -> action-+onDragEnd action = on "dragend" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/dragend+onDragEndWithOptions :: Options -> action -> Attribute action+onDragEndWithOptions options action =+ onWithOptions BUBBLE options "dragend" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/dragenter onDragEnter :: action -> Attribute action-onDragEnter action = on "dragenter" emptyDecoder $ \() -> action-+onDragEnter action = on "dragenter" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/dragenter+onDragEnterWithOptions :: Options -> action -> Attribute action+onDragEnterWithOptions options action =+ onWithOptions BUBBLE options "dragenter" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/dragleave onDragLeave :: action -> Attribute action-onDragLeave action = on "dragleave" emptyDecoder $ \() -> action-+onDragLeave action = on "dragleave" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/dragleave+onDragLeaveWithOptions :: Options -> action -> Attribute action+onDragLeaveWithOptions options action =+ onWithOptions BUBBLE options "dragleave" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/drag onDrag :: action -> Attribute action-onDrag action = on "drag" emptyDecoder $ \() -> action-+onDrag action = on "drag" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/drag+onDragWithOptions :: Options -> action -> Attribute action+onDragWithOptions options action =+ onWithOptions BUBBLE options "drag" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/drop-onDrop :: AllowDrop -> action -> Attribute action-onDrop (AllowDrop allowDrop) action =- onWithOptions defaultOptions { preventDefault = allowDrop }- "drop" emptyDecoder (\() -> action)-+onDrop :: Options -> action -> Attribute action+onDrop options action =+ onWithOptions BUBBLE options "drop" emptyDecoder (\() _ -> action)+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/drop+onDropWithOptions :: Options -> action -> Attribute action+onDropWithOptions options action =+ onWithOptions BUBBLE options "drop" emptyDecoder (\() _ -> action)+----------------------------------------------------------------------------- -- | https://developer.mozilla.org/en-US/docs/Web/Events/submit+--+-- Note: This has `preventDefault` enabled by default.+-- onSubmit :: action -> Attribute action onSubmit action =- onWithOptions defaultOptions { preventDefault = True }- "submit" emptyDecoder $ \() -> action+ onWithOptions BUBBLE preventDefault+ "submit" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointerup+onPointerUp :: (PointerEvent -> action) -> Attribute action+onPointerUp f = on "pointerup" pointerDecoder (\action _ -> f action)+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointerdown+onPointerDown :: (PointerEvent -> action) -> Attribute action+onPointerDown f = on "pointerdown" pointerDecoder (\action _ -> f action)+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointerenter+onPointerEnter :: (PointerEvent -> action) -> Attribute action+onPointerEnter f = on "pointerenter" pointerDecoder (\action _ -> f action)+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointerleave+onPointerLeave :: (PointerEvent -> action) -> Attribute action+onPointerLeave f = on "pointerleave" pointerDecoder (\action _ -> f action)+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointerover+onPointerOver :: (PointerEvent -> action) -> Attribute action+onPointerOver f = on "pointerover" pointerDecoder (\action _ -> f action)+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointerout+onPointerOut :: (PointerEvent -> action) -> Attribute action+onPointerOut f = on "pointerout" pointerDecoder (\action _ -> f action)+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointercancel+onPointerCancel :: (PointerEvent -> action) -> Attribute action+onPointerCancel f = on "pointercancel" pointerDecoder (\action _ -> f action)+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/pointermove+onPointerMove :: (PointerEvent -> action) -> Attribute action+onPointerMove f = on "pointermove" pointerDecoder (\action _ -> f action)+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_abort.asp+onAbort :: action -> Attribute action+onAbort action = on "abort" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_abort.asp+onAbortWith :: (Media -> action) -> Attribute action+onAbortWith action = on "abort" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_canplay.asp+onCanPlay :: action -> Attribute action+onCanPlay action = on "canplay" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_canplay.asp+onCanPlayWith :: (Media -> action) -> Attribute action+onCanPlayWith action = on "canplay" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_canplaythrough.asp+onCanPlayThrough :: action -> Attribute action+onCanPlayThrough action = on "canplaythrough" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_canplaythrough.asp+onCanPlayThroughWith :: (Media -> action) -> Attribute action+onCanPlayThroughWith action = on "canplaythrough" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_durationchange.asp+onDurationChange :: action -> Attribute action+onDurationChange action = on "durationchange" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_durationchange.asp+onDurationChangeWith :: (Media -> action) -> Attribute action+onDurationChangeWith action = on "durationchange" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/jsref/event_onemptied.asp+onEmptied :: action -> Attribute action+onEmptied action = on "emptied" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/jsref/event_onemptied.asp+onEmptiedWith :: (Media -> action) -> Attribute action+onEmptiedWith action = on "emptied" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_ended.asp+onEnded :: action -> Attribute action+onEnded action = on "ended" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_ended.asp+onEndedWith :: (Media -> action) -> Attribute action+onEndedWith action = on "ended" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_error.asp+onError :: action -> Attribute action+onError action = on "error" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_error.asp+onErrorWith :: (Media -> action) -> Attribute action+onErrorWith action = on "error" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/jsref/event_onload.asp+onLoad :: action -> Attribute action+onLoad action = on "load" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | onUnload event+onUnload :: action -> Attribute action+onUnload action = on "unload" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_loadeddata.asp+onLoadedData :: action -> Attribute action+onLoadedData action = on "loadeddata" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_loadeddata.asp+onLoadedDataWith :: (Media -> action) -> Attribute action+onLoadedDataWith action = on "loadeddata" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_loadedmetadata.asp+onLoadedMetadata :: action -> Attribute action+onLoadedMetadata action = on "loadedmetadata" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_loadedmetadata.asp+onLoadedMetadataWith :: (Media -> action) -> Attribute action+onLoadedMetadataWith action = on "loadedmetadata" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_loadstart.asp+onLoadStart :: action -> Attribute action+onLoadStart action = on "loadstart" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_loadstart.asp+onLoadStartWith :: (Media -> action) -> Attribute action+onLoadStartWith action = on "loadstart" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_pause.asp+onPause :: action -> Attribute action+onPause action = on "pause" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_pause.asp+onPauseWith :: (Media -> action) -> Attribute action+onPauseWith action = on "pause" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_play.asp+onPlay :: action -> Attribute action+onPlay action = on "play" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_play.asp+onPlayWith :: (Media -> action) -> Attribute action+onPlayWith action = on "play" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_playing.asp+onPlaying :: action -> Attribute action+onPlaying action = on "playing" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_playing.asp+onPlayingWith :: (Media -> action) -> Attribute action+onPlayingWith action = on "playing" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_progress.asp+onProgress :: action -> Attribute action+onProgress action = on "progress" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_progress.asp+onProgressWith :: (Media -> action) -> Attribute action+onProgressWith action = on "progress" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_ratechange.asp+onRateChange :: action -> Attribute action+onRateChange action = on "ratechange" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_ratechange.asp+onRateChangeWith :: (Media -> action) -> Attribute action+onRateChangeWith action = on "ratechange" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_seeked.asp+onSeeked :: action -> Attribute action+onSeeked action = on "seeked" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_seeked.asp+onSeekedWith :: (Media -> action) -> Attribute action+onSeekedWith action = on "seeked" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_seeking.asp+onSeeking :: action -> Attribute action+onSeeking action = on "seeking" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_seeking.asp+onSeekingWith :: (Media -> action) -> Attribute action+onSeekingWith action = on "seeking" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_stalled.asp+onStalled :: action -> Attribute action+onStalled action = on "stalled" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_stalled.asp+onStalledWith :: (Media -> action) -> Attribute action+onStalledWith action = on "stalled" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_suspend.asp+onSuspend :: action -> Attribute action+onSuspend action = on "suspend" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_suspend.asp+onSuspendWith :: (Media -> action) -> Attribute action+onSuspendWith action = on "suspend" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_timeupdate.asp+onTimeUpdate :: action -> Attribute action+onTimeUpdate action = on "timeupdate" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_timeupdate.asp+onTimeUpdateWith :: (Media -> action) -> Attribute action+onTimeUpdateWith action = on "timeupdate" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_volumechange.asp+onVolumeChange :: action -> Attribute action+onVolumeChange action = on "volumechange" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_volumechange.asp+onVolumeChangeWith :: (Media -> action) -> Attribute action+onVolumeChangeWith action = on "volumechange" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_waiting.asp+onWaiting :: action -> Attribute action+onWaiting action = on "waiting" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://www.w3schools.com/tags/av_event_waiting.asp+onWaitingWith :: (Media -> action) -> Attribute action+onWaitingWith action = on "waiting" emptyDecoder $ \() -> action . Media+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchstart+onTouchStart :: action -> Attribute action+onTouchStart action = on "touchstart" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchstart+onTouchStartWithOptions :: Options -> action -> Attribute action+onTouchStartWithOptions options action = onWithOptions BUBBLE options "touchstart" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchend+onTouchEnd :: action -> Attribute action+onTouchEnd action = on "touchend" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchend+onTouchEndWithOptions :: Options -> action -> Attribute action+onTouchEndWithOptions options action = onWithOptions BUBBLE options "touchend" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchmove+onTouchMove :: action -> Attribute action+onTouchMove action = on "touchmove" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchmove+onTouchMoveWithOptions :: Options -> action -> Attribute action+onTouchMoveWithOptions options action = onWithOptions BUBBLE options "touchmove" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchcancel+onTouchCancel :: action -> Attribute action+onTouchCancel action = on "touchcancel" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------+-- | https://developer.mozilla.org/en-US/docs/Web/Events/touchcancel+onTouchCancelWithOptions :: Options -> action -> Attribute action+onTouchCancelWithOptions options action = onWithOptions BUBBLE options "touchcancel" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------
src/Miso/Html/Property.hs view
@@ -1,9 +1,9 @@+----------------------------------------------------------------------------- {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE CPP #-} ----------------------------------------------------------------------------- -- | -- Module : Miso.Html.Property--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental@@ -11,31 +11,26 @@ -- -- Construct custom properties on DOM elements ----- > div_ [ prop "id" "foo" ] [ ]+-- > div_ [ id_ "miso" ] [ "miso" ] -- ---------------------------------------------------------------------------- module Miso.Html.Property- ( -- * Construction- textProp- , stringProp- , boolProp- , intProp- , integerProp- , doubleProp- -- * Common attributes- , class_+ ( -- *** Combinators+ class_+ , className+ , classes_ , classList_ , id_ , title_ , hidden_- -- * Inputs+ , inert_+ , lang_ , type_ , value_ , defaultValue_ , checked_ , placeholder_ , selected_- -- * Input Helpers , accept_ , acceptCharset_ , action_@@ -51,7 +46,7 @@ , method_ , multiple_ , name_- , novalidate_+ , noValidate_ , pattern_ , readonly_ , required_@@ -59,15 +54,12 @@ , for_ , ref_ , form_- -- * Input Ranges , max_ , min_ , step_- -- * Input Text areas , cols_ , rows_ , wrap_- -- * Links and areas , href_ , target_ , download_@@ -76,40 +68,40 @@ , media_ , ping_ , rel_- -- * Maps , ismap_ , usemap_ , shape_ , coords_- -- * Embedded Content , src_ , height_ , width_ , alt_ , loading_- -- * Audio and Video , autoplay_+ , currentTime_+ , defaultMuted_+ , volume_ , controls_ , loop_+ , defaultPlaybackRate_+ , mediaGroup_+ , muted_+ , playbackRate_+ , seeking_ , preload_ , poster_ , default_ , kind_ , srclang_- -- * iframes , sandbox_ , seamless_ , srcdoc_- -- * Ordered lists , reversed_- , start_- -- * Tables , align_ , colspan_ , rowspan_ , headers_ , scope_- -- * Headers , async_ , charset_ , content_@@ -117,296 +109,451 @@ , httpEquiv_ , language_ , scoped_- -- * Data , data_- , styleInline_+ , autocorrect_+ , spellcheck_+ , role_+ , xmlns_+ , aria_+ , label_+ , draggable_+ , frameborder_+ , scrolling_+ , tabindex_+ , open_ ) where--import Miso.Html.Types-import Miso.String (MisoString, intercalate)--#if __GLASGOW_HASKELL__ < 841-import Data.Monoid ((<>))-#endif---- | Set field to `Bool` value-boolProp :: MisoString -> Bool -> Attribute action-boolProp = prop--- | Set field to `String` value-stringProp :: MisoString -> String -> Attribute action-stringProp = prop--- | Set field to `Text` value-textProp :: MisoString -> MisoString -> Attribute action-textProp = prop--- | Set field to `Int` value-intProp :: MisoString -> Int -> Attribute action-intProp = prop--- | Set field to `Integer` value-integerProp :: MisoString -> Int -> Attribute action-integerProp = prop--- | Set field to `Double` value-doubleProp :: MisoString -> Double -> Attribute action-doubleProp = prop+-----------------------------------------------------------------------------+import Miso.Types+import Miso.Property+----------------------------------------------------------------------------- -- | Define multiple classes conditionally -- -- > div_ [ classList_ [ ("empty", null items) ] [ ] ---classList_ :: [(MisoString, Bool)] -> Attribute action-classList_ xs =- textProp "class" $ intercalate (" " :: MisoString) [ t | (t, True) <- xs ]--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/title>-title_ :: MisoString -> Attribute action+classList_ :: [(MisoString, Bool)] -> Attribute action+classList_ xs = classList [ t | (t, True) <- xs ]+-----------------------------------------------------------------------------+-- | Define multiple classes+--+-- > div_ [ classes_ [ "red", "warning" ] ] []+--+classes_ :: [MisoString] -> Attribute action+classes_ = classList+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title>+title_ :: MisoString -> Attribute action title_ = textProp "title"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/selected>-selected_ :: Bool -> Attribute action+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option#selected>+selected_ :: Bool -> Attribute action selected_ = boolProp "selected"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/hidden>-hidden_ :: Bool -> Attribute action-hidden_ = boolProp "hidden"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/value>-value_ :: MisoString -> Attribute action-value_ = textProp "value"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/defaultValue>-defaultValue_ :: MisoString -> Attribute action-defaultValue_ = textProp "defaultValue"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/accept>-accept_ :: MisoString -> Attribute action-accept_ = textProp "accept"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/acceptCharset>-acceptCharset_ :: MisoString -> Attribute action-acceptCharset_ = textProp "acceptCharset"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/action>-action_ :: MisoString -> Attribute action-action_ = textProp "action"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/autocomplete>-autocomplete_ :: Bool -> Attribute action+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/hidden>+hidden_ :: Bool -> Attribute action+hidden_ = boolProp "hidden"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inert>+inert_ :: Bool -> Attribute action+inert_ = boolProp "inert"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang>+lang_ :: MisoString -> Attribute action+lang_ = textProp "lang"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/value>+value_ :: MisoString -> Attribute action+value_ = textProp "value"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/defaultValue>+defaultValue_ :: MisoString -> Attribute action+defaultValue_ = textProp "defaultValue"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept>+accept_ :: MisoString -> Attribute action+accept_ = textProp "accept"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/acceptCharset>+acceptCharset_ :: MisoString -> Attribute action+acceptCharset_ = textProp "acceptCharset"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/action>+action_ :: MisoString -> Attribute action+action_ = textProp "action"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autocomplete>+autocomplete_ :: Bool -> Attribute action autocomplete_ b = textProp "autocomplete" (if b then "on" else "off")--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/autosave>-autosave_ :: MisoString -> Attribute action-autosave_ = textProp "autosave"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/disabled>-disabled_ :: Bool -> Attribute action-disabled_ = boolProp "disabled"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/enctype>-enctype_ :: MisoString -> Attribute action-enctype_ = textProp "enctype"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/formation>-formation_ :: MisoString -> Attribute action-formation_ = textProp "formation"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/list>-list_ :: MisoString -> Attribute action-list_ = textProp "list"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/maxlength>-maxlength_ :: MisoString -> Attribute action-maxlength_ = textProp "maxlength"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/minlength>-minlength_ :: MisoString -> Attribute action-minlength_ = textProp "minlength"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/method>-method_ :: MisoString -> Attribute action-method_ = textProp "method"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/multiple>-multiple_ :: Bool -> Attribute action-multiple_ = boolProp "multiple"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/novalidate>-novalidate_ :: Bool -> Attribute action-novalidate_ = boolProp "noValidate"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/pattern>-pattern_ :: MisoString -> Attribute action-pattern_ = textProp "pattern"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/readonly>-readonly_ :: Bool -> Attribute action-readonly_ = boolProp "readOnly"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/required>-required_ :: Bool -> Attribute action-required_ = boolProp "required"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/size>-size_ :: MisoString -> Attribute action-size_ = textProp "size"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/for>-for_ :: MisoString -> Attribute action-for_ = textProp "for"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/ref>-ref_ :: MisoString -> Attribute action-ref_ = textProp "ref"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/form>-form_ :: MisoString -> Attribute action-form_ = textProp "form"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/max>-max_ :: MisoString -> Attribute action-max_ = textProp "max"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/min>-min_ :: MisoString -> Attribute action-min_ = textProp "min"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/step>-step_ :: MisoString -> Attribute action-step_ = textProp "step"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/cols>-cols_ :: MisoString -> Attribute action-cols_ = textProp "cols"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/rows>-rows_ :: MisoString -> Attribute action-rows_ = textProp "rows"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/wrap>-wrap_ :: MisoString -> Attribute action-wrap_ = textProp "wrap"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/target>-target_ :: MisoString -> Attribute action-target_ = textProp "target"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/download>-download_ :: MisoString -> Attribute action-download_ = textProp "download"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/downloadAs>-downloadAs_ :: MisoString -> Attribute action-downloadAs_ = textProp "downloadAs"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/hreflang>-hreflang_ :: MisoString -> Attribute action-hreflang_ = textProp "hreflang"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/media>-media_ :: MisoString -> Attribute action-media_ = textProp "media"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/ping>-ping_ :: MisoString -> Attribute action-ping_ = textProp "ping"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/rel>-rel_ :: MisoString -> Attribute action-rel_ = textProp "rel"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/ismap>-ismap_ :: MisoString -> Attribute action-ismap_ = textProp "ismap"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/usemap>-usemap_ :: MisoString -> Attribute action-usemap_ = textProp "usemap"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/shape>-shape_ :: MisoString -> Attribute action-shape_ = textProp "shape"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/coords>-coords_ :: MisoString -> Attribute action-coords_ = textProp "coords"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/src>-src_ :: MisoString -> Attribute action-src_ = textProp "src"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/height>-height_ :: MisoString -> Attribute action-height_ = textProp "height"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/width>-width_ :: MisoString -> Attribute action-width_ = textProp "width"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/alt>-alt_ :: MisoString -> Attribute action-alt_ = textProp "alt"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/loading>-loading_ :: MisoString -> Attribute action-loading_ = textProp "loading"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/autoplay>-autoplay_ :: Bool -> Attribute action-autoplay_ = boolProp "autoplay"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/controls>-controls_ :: Bool -> Attribute action-controls_ = boolProp "controls"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/loop>-loop_ :: Bool -> Attribute action-loop_ = boolProp "loop"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/preload>-preload_ :: MisoString -> Attribute action-preload_ = textProp "preload"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/poster>-poster_ :: MisoString -> Attribute action-poster_ = textProp "poster"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/default>-default_ :: Bool -> Attribute action-default_ = boolProp "default"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/kind>-kind_ :: MisoString -> Attribute action-kind_ = textProp "kind"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/srclang>-srclang_ :: MisoString -> Attribute action-srclang_ = textProp "srclang"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/sandbox>-sandbox_ :: MisoString -> Attribute action-sandbox_ = textProp "sandbox"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/seamless>-seamless_ :: MisoString -> Attribute action-seamless_ = textProp "seamless"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/srcdoc>-srcdoc_ :: MisoString -> Attribute action-srcdoc_ = textProp "srcdoc"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/reversed>-reversed_ :: MisoString -> Attribute action-reversed_ = textProp "reversed"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/start>-start_ :: MisoString -> Attribute action-start_ = textProp "start"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/align>-align_ :: MisoString -> Attribute action-align_ = textProp "align"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/colspan>-colspan_ :: MisoString -> Attribute action-colspan_ = textProp "colspan"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/rowspan>-rowspan_ :: MisoString -> Attribute action-rowspan_ = textProp "rowspan"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/headers>-headers_ :: MisoString -> Attribute action-headers_ = textProp "headers"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/scope>-scope_ :: MisoString -> Attribute action-scope_ = textProp "scope"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/async>-async_ :: MisoString -> Attribute action-async_ = textProp "async"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/charset>-charset_ :: MisoString -> Attribute action-charset_ = textProp "charset"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/content>-content_ :: MisoString -> Attribute action-content_ = textProp "content"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/defer>-defer_ :: MisoString -> Attribute action-defer_ = textProp "defer"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/httpEquiv>-httpEquiv_ :: MisoString -> Attribute action-httpEquiv_ = textProp "httpEquiv"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/language>-language_ :: MisoString -> Attribute action-language_ = textProp "language"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/scoped>-scoped_ :: MisoString -> Attribute action-scoped_ = textProp "scoped"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/type>-type_ :: MisoString -> Attribute action+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autosave>+autosave_ :: MisoString -> Attribute action+autosave_ = textProp "autosave"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autocorrect>+autocorrect_ :: Bool -> Attribute action+autocorrect_ b = textProp "autocomplete" (if b then "on" else "off")+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/spellcheck>+spellcheck_ :: Bool -> Attribute action+spellcheck_ b = textProp "autocomplete" (if b then "on" else "off")+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/role>+role_ :: MisoString -> Attribute action+role_ = textProp "role"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled>+disabled_ :: Attribute action+disabled_ = boolProp "disabled" True+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/enctype>+enctype_ :: MisoString -> Attribute action+enctype_ = textProp "enctype"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/formation>+formation_ :: MisoString -> Attribute action+formation_ = textProp "formation"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/list>+list_ :: MisoString -> Attribute action+list_ = textProp "list"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/maxlength>+maxlength_ :: MisoString -> Attribute action+maxlength_ = textProp "maxlength"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/minlength>+minlength_ :: MisoString -> Attribute action+minlength_ = textProp "minlength"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/method>+method_ :: MisoString -> Attribute action+method_ = textProp "method"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/multiple>+multiple_ :: Bool -> Attribute action+multiple_ = boolProp "multiple"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/noValidate>+noValidate_ :: Bool -> Attribute action+noValidate_ = boolProp "noValidate"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/pattern>+pattern_ :: MisoString -> Attribute action+pattern_ = textProp "pattern"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/details#open>+open_ :: Bool -> Attribute action+open_ = boolProp "open"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly>+readonly_ :: Bool -> Attribute action+readonly_ = boolProp "readOnly"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/required>+required_ :: Bool -> Attribute action+required_ = boolProp "required"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/size>+size_ :: MisoString -> Attribute action+size_ = textProp "size"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/for>+for_ :: MisoString -> Attribute action+for_ = textProp "for"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/ref>+ref_ :: MisoString -> Attribute action+ref_ = textProp "ref"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/form>+form_ :: MisoString -> Attribute action+form_ = textProp "form"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/max>+max_ :: MisoString -> Attribute action+max_ = textProp "max"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/min>+min_ :: MisoString -> Attribute action+min_ = textProp "min"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/step>+step_ :: MisoString -> Attribute action+step_ = textProp "step"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/cols>+cols_ :: MisoString -> Attribute action+cols_ = textProp "cols"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/rows>+rows_ :: MisoString -> Attribute action+rows_ = textProp "rows"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/wrap>+wrap_ :: MisoString -> Attribute action+wrap_ = textProp "wrap"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/target>+target_ :: MisoString -> Attribute action+target_ = textProp "target"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/download>+download_ :: MisoString -> Attribute action+download_ = textProp "download"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/downloadAs>+downloadAs_ :: MisoString -> Attribute action+downloadAs_ = textProp "downloadAs"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/hreflang>+hreflang_ :: MisoString -> Attribute action+hreflang_ = textProp "hreflang"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/media>+media_ :: MisoString -> Attribute action+media_ = textProp "media"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/ping>+ping_ :: MisoString -> Attribute action+ping_ = textProp "ping"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/rel>+rel_ :: MisoString -> Attribute action+rel_ = textProp "rel"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/isMap>+ismap_ :: Bool -> Attribute action+ismap_ = boolProp "ismap"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/usemap>+usemap_ :: MisoString -> Attribute action+usemap_ = textProp "usemap"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/shape>+shape_ :: MisoString -> Attribute action+shape_ = textProp "shape"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/coords>+coords_ :: MisoString -> Attribute action+coords_ = textProp "coords"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/src>+src_ :: MisoString -> Attribute action+src_ = textProp "src"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/height>+height_ :: MisoString -> Attribute action+height_ = textProp "height"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/width>+width_ :: MisoString -> Attribute action+width_ = textProp "width"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/alt>+alt_ :: MisoString -> Attribute action+alt_ = textProp "alt"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/loading>+loading_ :: MisoString -> Attribute action+loading_ = textProp "loading"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/autoplay>+autoplay_ :: Bool -> Attribute action+autoplay_ = boolProp "autoplay"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/currentTime>+currentTime_ :: Double -> Attribute action+currentTime_ = doubleProp "currentTime"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/defaultMuted>+defaultMuted_ :: Bool -> Attribute action+defaultMuted_ = boolProp "defaultMuted"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/defaultPlaybackRate>+defaultPlaybackRate_ :: Double -> Attribute action+defaultPlaybackRate_ = doubleProp "defaultPlaybackRate"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/mediaGroup>+mediaGroup_ :: MisoString -> Attribute action+mediaGroup_ = textProp "mediaGroup"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/muted>+muted_ :: Bool -> Attribute action+muted_ = boolProp "muted"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/playbackRate>+playbackRate_ :: Double -> Attribute action+playbackRate_ = doubleProp "playbackRate"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/preload>+preload_ :: MisoString -> Attribute action+preload_ = textProp "preload"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/seeking>+seeking_ :: Bool -> Attribute action+seeking_ = boolProp "seeking"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/volume>+volume_ :: Double -> Attribute action+volume_ = doubleProp "volume"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/controls>+controls_ :: Bool -> Attribute action+controls_ = boolProp "controls"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/loop>+loop_ :: Bool -> Attribute action+loop_ = boolProp "loop"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/poster>+poster_ :: MisoString -> Attribute action+poster_ = textProp "poster"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/default>+default_ :: Bool -> Attribute action+default_ = boolProp "default"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/kind>+kind_ :: MisoString -> Attribute action+kind_ = textProp "kind"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/srclang>+srclang_ :: MisoString -> Attribute action+srclang_ = textProp "srclang"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/sandbox>+sandbox_ :: MisoString -> Attribute action+sandbox_ = textProp "sandbox"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/seamless>+seamless_ :: MisoString -> Attribute action+seamless_ = textProp "seamless"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/srcdoc>+srcdoc_ :: MisoString -> Attribute action+srcdoc_ = textProp "srcdoc"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/ol#reversed>+reversed_ :: Bool -> Attribute action+reversed_ = boolProp "reversed"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/align>+align_ :: MisoString -> Attribute action+align_ = textProp "align"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/colspan>+colspan_ :: MisoString -> Attribute action+colspan_ = textProp "colspan"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/rowspan>+rowspan_ :: MisoString -> Attribute action+rowspan_ = textProp "rowspan"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/headers>+headers_ :: MisoString -> Attribute action+headers_ = textProp "headers"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/scope>+scope_ :: MisoString -> Attribute action+scope_ = textProp "scope"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/async>+async_ :: Bool -> Attribute action+async_ = boolProp "async"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/charset>+charset_ :: MisoString -> Attribute action+charset_ = textProp "charset"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/content>+content_ :: MisoString -> Attribute action+content_ = textProp "content"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement/defer>+defer_ :: Bool -> Attribute action+defer_ = boolProp "defer"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/httpEquiv>+httpEquiv_ :: MisoString -> Attribute action+httpEquiv_ = textProp "httpEquiv"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/language>+language_ :: MisoString -> Attribute action+language_ = textProp "language"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/scoped>+scoped_ :: MisoString -> Attribute action+scoped_ = textProp "scoped"+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/type>+type_ :: MisoString -> Attribute action type_ = textProp "type"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/name>-name_ :: MisoString -> Attribute action+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement/name>+name_ :: MisoString -> Attribute action name_ = textProp "name"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/href>-href_ :: MisoString -> Attribute action+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement/href>+href_ :: MisoString -> Attribute action href_ = textProp "href"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/id>-id_ :: MisoString -> Attribute action+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id>+id_ :: MisoString -> Attribute action id_ = textProp "id"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/placeholder>-placeholder_ :: MisoString -> Attribute action+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/placeholder>+placeholder_ :: MisoString -> Attribute action placeholder_ = textProp "placeholder"--- | <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/checked>-checked_ :: Bool -> Attribute action+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/checked>+checked_ :: Bool -> Attribute action checked_ = boolProp "checked"--- | Set "autofocus" property--- <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/autofocus>-autofocus_ :: Bool -> Attribute action+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus>+autofocus_ :: Bool -> Attribute action autofocus_ = boolProp "autofocus"+----------------------------------------------------------------------------- -- | Set "className" property -- <https://developer.mozilla.org/en-US/docs/Web/API/Element/className>-class_ :: MisoString -> Attribute action-class_ = textProp "class"+class_ :: MisoString -> Attribute action+class_ = className+-----------------------------------------------------------------------------+-- | Set "className" property+-- <https://developer.mozilla.org/en-US/docs/Web/API/Element/className>+className :: MisoString -> Attribute action+className name = classList [name]+----------------------------------------------------------------------------- -- | Set "data-*" property -- https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-*-data_ :: MisoString -> MisoString -> Attribute action+data_ :: MisoString -> MisoString -> Attribute action data_ k v = textProp ("data-" <> k) v--- | Set "style" property------ > view m = div_ [ styleInline_ "background-color:red;color:blue;" ] [ "foo" ]+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+xmlns_ :: MisoString -> Attribute action+xmlns_ = textProp "xmlns"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+aria_ :: MisoString -> MisoString -> Attribute action+aria_ k = textProp ("aria-" <> k)+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+label_ :: MisoString -> Attribute action+label_ = textProp "label"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+draggable_ :: Bool -> Attribute action+draggable_ = boolProp "draggable"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+scrolling_ :: MisoString -> Attribute action+scrolling_ = textProp "scrolling"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+frameborder_ :: MisoString -> Attribute action+frameborder_ = textProp "frameborder"+-----------------------------------------------------------------------------+-- | [tabindex](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/tabindex) attribute ----- https://developer.mozilla.org/en-US/docs/Web/CSS-styleInline_ :: MisoString -> Attribute action-styleInline_ = textProp "style"+-- @since 1.9.0.0+tabindex_ :: MisoString -> Attribute action+tabindex_ = textProp "tabindex"+-----------------------------------------------------------------------------
+ src/Miso/Html/Render.hs view
@@ -0,0 +1,222 @@+-----------------------------------------------------------------------------+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE CPP #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Html.Render+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- 'Miso.Types.View' serialization+--+----------------------------------------------------------------------------+module Miso.Html.Render+ ( -- *** Classes+ ToHtml (..)+ ) where+----------------------------------------------------------------------------+import qualified Data.Set as S+import Data.Set (Set)+import Data.ByteString.Builder+import qualified Data.ByteString.Lazy as L+import qualified Data.Map.Strict as M+import Unsafe.Coerce (unsafeCoerce)+#ifdef SSR+import Control.Exception (SomeException, catch)+import System.IO.Unsafe (unsafePerformIO)+#endif+----------------------------------------------------------------------------+import Miso.JSON+import Miso.String hiding (intercalate)+import qualified Miso.String as MS+import Miso.Types+----------------------------------------------------------------------------+-- | Class for rendering HTML+class ToHtml a where+ toHtml :: a -> L.ByteString+----------------------------------------------------------------------------+-- | Render a @Miso.Types.View@ to a @L.ByteString@+instance ToHtml (Miso.Types.View m a) where+ toHtml = renderView+----------------------------------------------------------------------------+-- | Render a @[Miso.Types.View]@ to a @L.ByteString@+instance ToHtml [Miso.Types.View m a] where+ toHtml = foldMap renderView+----------------------------------------------------------------------------+renderView :: View m a -> L.ByteString+renderView = toLazyByteString . renderBuilder+----------------------------------------------------------------------------+intercalate :: Builder -> [Builder] -> Builder+intercalate _ [] = ""+intercalate _ [x] = x+intercalate sep (x:xs) =+ mconcat+ [ x+ , sep+ , intercalate sep xs+ ]+----------------------------------------------------------------------------+booleanProperties :: Set MisoString+booleanProperties = S.fromList+ [ "allowfullscreen"+ , "allowpaymentrequest"+ , "allowusermedia"+ , "async"+ , "autofocus"+ , "autoplay"+ , "checked"+ , "controls"+ , "default"+ , "defer"+ , "disabled"+ , "download"+ , "formnovalidate"+ , "hidden"+ , "inert"+ , "ismap"+ , "itemscope"+ , "loop"+ , "multiple"+ , "muted"+ , "nomodule"+ , "novalidate"+ , "open"+ , "playsinline"+ , "readonly"+ , "required"+ , "reversed"+ , "selected"+ , "truespeed"+ ]+----------------------------------------------------------------------------+renderBuilder :: Miso.Types.View m a -> Builder+renderBuilder (VText _ "") = fromMisoString " "+renderBuilder (VText _ s) = fromMisoString s+renderBuilder (VNode _ "doctype" [] []) = "<!doctype html>"+renderBuilder (VNode ns tag attrs children) = mconcat+ [ "<"+ , fromMisoString tag+ , mconcat [ " " <> intercalate " " (renderAttrs <$> attrs)+ | not (Prelude.null attrs)+ ]+ , if tag `elem` selfClosing then "/>" else ">"+ , mconcat+ [ mconcat+ [ foldMap renderBuilder (collapseSiblingTextNodes children)+ , "</" <> fromMisoString tag <> ">"+ ]+ | tag `notElem` selfClosing+ ]+ ] where+ selfClosing = htmls <> svgs <> mathmls+ htmls = [ x+ | x <- [ "area", "base", "col", "embed", "img", "input", "br", "hr", "meta", "link", "param", "source", "track", "wbr" ]+ , ns == HTML+ ]+ svgs = [ x+ | x <- [ "circle", "line", "rect", "path", "ellipse", "polygon", "polyline", "use", "image"]+ , ns == SVG+ ]+ mathmls =+ [ x+ | x <- ["mglyph", "mprescripts", "none", "maligngroup", "malignmark" ]+ , ns == MATHML+ ]++renderBuilder (VComp _ (SomeComponent vcomp_)) =+ foldMap renderBuilder vkids+ where+#ifdef SSR+ vkids = [ unsafeCoerce $ (view vcomp_) $ getInitialComponentModel vcomp_ ]+#else+ vkids = [ unsafeCoerce $ (view vcomp_) (model vcomp_) ]+#endif+----------------------------------------------------------------------------+renderAttrs :: Attribute action -> Builder+renderAttrs (ClassList classes) =+ mconcat+ [ "class"+ , stringUtf8 "=\""+ , fromMisoString (MS.unwords classes)+ , stringUtf8 "\""+ ]+renderAttrs (Property key (Bool enabled)) -- dmj: account for boolean properties+ | S.member key booleanProperties, enabled = fromMisoString key+ | S.member key booleanProperties, not enabled = mempty+ | otherwise = mconcat+ [ fromMisoString key+ , stringUtf8 "=\""+ , toHtmlFromJSON (Bool enabled)+ , stringUtf8 "\""+ ]+renderAttrs (Property "key" _) = mempty+renderAttrs (Property key value) =+ mconcat+ [ fromMisoString key+ , stringUtf8 "=\""+ , toHtmlFromJSON value+ , stringUtf8 "\""+ ]+renderAttrs (On _) = mempty+renderAttrs (Styles styles) =+ mconcat+ [ "style"+ , stringUtf8 "=\""+ , mconcat+ [ mconcat+ [ fromMisoString k+ , charUtf8 ':'+ , fromMisoString v+ , charUtf8 ';'+ ]+ | (k,v) <- M.toList styles+ ]+ , stringUtf8 "\""+ ]+----------------------------------------------------------------------------+-- | The browser can't distinguish between multiple text nodes+-- and a single text node. So it will always parse a single text node+-- this means we must collapse adjacent text nodes during hydration.+collapseSiblingTextNodes :: [View m a] -> [View m a]+collapseSiblingTextNodes [] = []+collapseSiblingTextNodes (VText _ x : VText k y : xs) =+ collapseSiblingTextNodes (VText k (x <> y) : xs)+collapseSiblingTextNodes (x:xs) =+ x : collapseSiblingTextNodes xs+----------------------------------------------------------------------------+-- | Helper for turning JSON into Text+-- Object, Array and Null are kind of non-sensical here+toHtmlFromJSON :: Value -> Builder+toHtmlFromJSON (String t) = fromMisoString (ms t)+toHtmlFromJSON (Number t) = fromMisoString $ ms (show t)+toHtmlFromJSON (Bool True) = "true"+toHtmlFromJSON (Bool False) = "false"+toHtmlFromJSON Null = "null"+toHtmlFromJSON (Object o) = fromMisoString $ ms (show o)+toHtmlFromJSON (Array a) = fromMisoString $ ms (show a)+-----------------------------------------------------------------------------+#ifdef SSR+-- | Used for server-side model hydration, internally only in 'renderView'.+--+-- We use 'unsafePerformIO' here because @servant@'s 'MimeRender' is a pure function+-- yet we need to allow the users to hydrate in 'IO'.+--+getInitialComponentModel :: Component parent model action -> model+getInitialComponentModel Component {..} =+ case hydrateModel of+ Nothing -> model+ Just action -> unsafePerformIO $+ action `catch` (\(e :: SomeException) -> do+ putStrLn "Encountered exception during model hydration, falling back to default model"+ print e+ pure model)+----------------------------------------------------------------------------+#endif
− src/Miso/Html/Types.hs
@@ -1,423 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}--module Miso.Html.Types (- -- * Core types and interface- VTree (..)- , View (..)- , ToView (..)- -- * `View` runner- , runView- -- * Smart `View` constructors- , node- , text- , textRaw- , rawHtml- -- * Core types and interface- , Attribute (..)- -- * Key patch internals- , Key (..)- , ToKey (..)- -- * Namespace- , NS(..)- -- * Setting properties on virtual DOM nodes- , prop- -- * Setting css- , style_- -- * Handling events- , on- , onWithOptions- -- * Life cycle events- , onCreated- , onDestroyed- , onBeforeDestroyed- ) where--import Control.Monad (forM_, (<=<))-import Control.Monad.IO.Class (liftIO)-import Data.Aeson (ToJSON, Value, toJSON)-import qualified Data.Aeson as A-import Data.Aeson.Types (parseEither)-import Data.JSString (JSString)-import qualified Data.Map as M-import Data.Proxy (Proxy(Proxy))-import Data.String (IsString, fromString)-import qualified Data.Text as T-import GHCJS.Marshal (ToJSVal, fromJSVal, toJSVal)-import GHCJS.Types (jsval)-import qualified JavaScript.Array as JSArray-import JavaScript.Object (create, getProp)-import JavaScript.Object.Internal (Object(Object))-import qualified Lucid as L-import qualified Lucid.Base as L-import Prelude hiding (null)-import Servant.API (Get, HasLink(MkLink, toLink))-import Text.HTML.TagSoup.Tree (parseTree, TagTree(..))-import Text.HTML.TagSoup (Tag(..))--import Miso.Effect-import Miso.Event-import Miso.FFI-import Miso.String hiding (reverse, elem)---- | Core type for constructing a `VTree`, use this instead of `VTree` directly.-data View action- = Node NS MisoString (Maybe Key) [Attribute action] [View action]- | Text MisoString- | TextRaw MisoString- deriving Functor---- | For constructing type-safe links-instance HasLink (View a) where-#if MIN_VERSION_servant(0,14,0)- type MkLink (View a) b = MkLink (Get '[] ()) b- toLink toA Proxy = toLink toA (Proxy :: Proxy (Get '[] ()))-#else- type MkLink (View a) = MkLink (Get '[] ())- toLink _ = toLink (Proxy :: Proxy (Get '[] ()))-#endif---- | Convenience class for using View-class ToView v where toView :: v -> View action---- | Create a new @Miso.Html.Types.TextRaw@.------ @expandable@--- a 'rawHtml' node takes raw HTML and attempts to convert it to a 'VTree'--- at runtime. This is a way to dynamically populate the virtual DOM from--- HTML received at runtime. If rawHtml cannot parse the HTML it will not render.-rawHtml- :: MisoString- -> View action-rawHtml = TextRaw----- | Create a new @Miso.Html.Types.Node@.------ @node ns tag key attrs children@ creates a new node with tag @tag@--- and 'Key' @key@ in the namespace @ns@. All @attrs@ are called when--- the node is created and its children are initialized to @children@.-node :: NS- -> MisoString- -> Maybe Key- -> [Attribute action]- -> [View action]- -> View action-node = Node---- | Create a new @Text@ with the given content.-text :: MisoString -> View action-text = Text---- | `TextRaw` creation. Don't use directly-textRaw :: MisoString -> View action-textRaw = TextRaw---- | `IsString` instance-instance IsString (View a) where- fromString = text . fromString---- | Converting `View` to Lucid's `L.Html`-instance L.ToHtml (View action) where- toHtmlRaw = L.toHtml- toHtml (Node _ vType _ attrs vChildren) = L.with ele lattrs- where- noEnd = ["img", "input", "br", "hr", "meta"]- tag = toTag $ fromMisoString vType- ele = if tag `elem` noEnd- then L.makeElementNoEnd tag- else L.makeElement tag kids- classes = T.intercalate " " [ v | P "class" (A.String v) <- attrs ]- propClass = M.fromList $ attrs >>= \case- P k v -> [(k, v)]- E _ -> []- S m -> [("style", A.String . fromMisoString $ M.foldrWithKey go mempty m)]- where- go :: MisoString -> MisoString -> MisoString -> MisoString- go k v ys = mconcat [ k, ":", v, ";" ] <> ys- xs = if not (T.null classes)- then M.insert "class" (A.String classes) propClass- else propClass- lattrs = [ L.makeAttribute k' (if k `elem` exceptions && v == A.Bool True then k' else v')- | (k,v) <- M.toList xs- , let k' = fromMisoString k- , let v' = toHtmlFromJSON v- , not (k `elem` exceptions && v == A.Bool False)- ]- exceptions = [ "checked"- , "disabled"- , "selected"- , "hidden"- , "readOnly"- , "autoplay"- , "required"- , "default"- , "autofocus"- , "multiple"- , "noValidate"- , "autocomplete"- ]- toTag = T.toLower- kids = foldMap L.toHtml $ collapseSiblingTextNodes vChildren- toHtml (Text x) | null x = L.toHtml (" " :: T.Text)- | otherwise = L.toHtml (fromMisoString x :: T.Text)- toHtml (TextRaw x)- | null x = L.toHtml (" " :: T.Text)- | otherwise = L.toHtmlRaw (fromMisoString x :: T.Text)--collapseSiblingTextNodes :: [View a] -> [View a]-collapseSiblingTextNodes [] = []-collapseSiblingTextNodes (Text x : Text y : xs) =- collapseSiblingTextNodes (Text (x <> y) : xs)--- TextRaw is the only child, so no need to collapse.-collapseSiblingTextNodes (x:xs) =- x : collapseSiblingTextNodes xs---- | Helper for turning JSON into Text--- Object, Array and Null are kind of non-sensical here-toHtmlFromJSON :: Value -> T.Text-toHtmlFromJSON (A.String t) = t-toHtmlFromJSON (A.Number t) = T.pack (show t)-toHtmlFromJSON (A.Bool b) = if b then "true" else "false"-toHtmlFromJSON A.Null = "null"-toHtmlFromJSON (A.Object o) = T.pack (show o)-toHtmlFromJSON (A.Array a) = T.pack (show a)---- | Virtual DOM implemented as a JavaScript `Object`.--- Used for diffing, patching and event delegation.--- Not meant to be constructed directly, see `View` instead.-newtype VTree = VTree { getTree :: Object }--runView :: View action -> Sink action -> JSM VTree-runView (Node ns tag key attrs kids) sink = do- vnode <- create- cssObj <- objectToJSVal =<< create- propsObj <- objectToJSVal =<< create- eventObj <- objectToJSVal =<< create- set "css" cssObj vnode- set "props" propsObj vnode- set "events" eventObj vnode- set "type" ("vnode" :: JSString) vnode- set "ns" ns vnode- set "tag" tag vnode- set "key" key vnode- setAttrs vnode- flip (set "children") vnode- =<< ghcjsPure . jsval- =<< setKids- pure $ VTree vnode- where- setAttrs vnode =- forM_ attrs $ \case- P k v -> do- val <- toJSVal v- o <- getProp "props" vnode- set k val (Object o)- E attr -> attr sink vnode- S m -> do- cssObj <- getProp "css" vnode- forM_ (M.toList m) $ \(k,v) -> do- set k v (Object cssObj)- setKids = do- kidsViews <- traverse (objectToJSVal . getTree <=< flip runView sink) kids- ghcjsPure (JSArray.fromList kidsViews)-runView (Text t) _ = do- vtree <- create- set "type" ("vtext" :: JSString) vtree- set "text" t vtree- pure $ VTree vtree-runView (TextRaw str) sink =- case parseView str of- [] ->- runView (Text (" " :: MisoString)) sink- [parent] ->- runView parent sink- kids -> do- runView (Node HTML "div" Nothing mempty kids) sink---- Filters tree to only branches and leaves w/ Text tags.--- converts to View a. Note: if HTML is malformed,--- (e.g. closing tags and opening tags are present) they will--- be removed.-parseView :: MisoString -> [View a]-parseView html = reverse (go (parseTree html) [])- where- go [] xs = xs- go (TagLeaf (TagText s) : next) views =- go next (Text s : views)- go (TagLeaf (TagOpen name attrs) : next) views =- go (TagBranch name attrs [] : next) views- go (TagBranch name attrs kids : next) views =- let- attrs' = [ P key $ A.String (fromMisoString val)- | (key, val) <- attrs- ]- newNode =- Node HTML name Nothing attrs' (reverse (go kids []))- in- go next (newNode:views)- go (TagLeaf _ : next) views =- go next views---- | Namespace of DOM elements.-data NS- = HTML -- ^ HTML Namespace- | SVG -- ^ SVG Namespace- | MATHML -- ^ MATHML Namespace- deriving (Show, Eq)--instance ToJSVal NS where- toJSVal SVG = toJSVal ("svg" :: JSString)- toJSVal HTML = toJSVal ("html" :: JSString)- toJSVal MATHML = toJSVal ("mathml" :: JSString)---- | A unique key for a dom node.------ This key is only used to speed up diffing the children of a DOM--- node, the actual content is not important. The keys of the children--- of a given DOM node must be unique. Failure to satisfy this--- invariant gives undefined behavior at runtime.-newtype Key = Key MisoString--instance ToJSVal Key where toJSVal (Key x) = toJSVal x---- | Convert custom key types to `Key`.------ Instances of this class do not have to guarantee uniqueness of the--- generated keys, it is up to the user to do so. `toKey` must be an--- injective function.-class ToKey key where toKey :: key -> Key--- | Identity instance-instance ToKey Key where toKey = id--- | Convert `MisoString` to `Key`-instance ToKey JSString where toKey = Key . toMisoString--- | Convert `T.Text` to `Key`-instance ToKey T.Text where toKey = Key . toMisoString--- | Convert `String` to `Key`-instance ToKey String where toKey = Key . toMisoString--- | Convert `Int` to `Key`-instance ToKey Int where toKey = Key . toMisoString--- | Convert `Double` to `Key`-instance ToKey Double where toKey = Key . toMisoString--- | Convert `Float` to `Key`-instance ToKey Float where toKey = Key . toMisoString--- | Convert `Word` to `Key`-instance ToKey Word where toKey = Key . toMisoString---- | Attribute of a vnode in a `View`.------ The 'Sink' callback can be used to dispatch actions which are fed back to--- the @update@ function. This is especially useful for event handlers--- like the @onclick@ attribute. The second argument represents the--- vnode the attribute is attached to.-data Attribute action- = P MisoString Value- | E (Sink action -> Object -> JSM ())- | S (M.Map MisoString MisoString)- deriving Functor---- | @prop k v@ is an attribute that will set the attribute @k@ of the DOM node associated with the vnode--- to @v@.-prop :: ToJSON a => MisoString -> a -> Attribute action-prop k v = P k (toJSON v)---- | Convenience wrapper for @onWithOptions defaultOptions@.------ > let clickHandler = on "click" emptyDecoder $ \() -> Action--- > in button_ [ clickHandler, class_ "add" ] [ text_ "+" ]----on :: MisoString- -> Decoder r- -> (r -> action)- -> Attribute action-on = onWithOptions defaultOptions---- | @onWithOptions opts eventName decoder toAction@ is an attribute--- that will set the event handler of the associated DOM node to a function that--- decodes its argument using @decoder@, converts it to an action--- using @toAction@ and then feeds that action back to the @update@ function.------ @opts@ can be used to disable further event propagation.------ > let clickHandler = onWithOptions defaultOptions "click" emptyDecoder $ \() -> Action--- > in button_ [ clickHandler, class_ "add" ] [ text_ "+" ]----onWithOptions- :: Options- -> MisoString- -> Decoder r- -> (r -> action)- -> Attribute action-onWithOptions options eventName Decoder{..} toAction =- E $ \sink n -> do- eventObj <- getProp "events" n- eventHandlerObject@(Object eo) <- create- jsOptions <- toJSVal options- decodeAtVal <- toJSVal decodeAt- cb <- callbackToJSVal <=< asyncCallback1 $ \e -> do- Just v <- fromJSVal =<< objectToJSON decodeAtVal e- case parseEither decoder v of- Left s -> error $ "Parse error on " <> unpack eventName <> ": " <> s- Right r -> liftIO (sink (toAction r))- set "runEvent" cb eventHandlerObject- registerCallback cb- set "options" jsOptions eventHandlerObject- set eventName eo (Object eventObj)---- | @onCreated action@ is an event that gets called after the actual DOM--- element is created.------ Important note: Any node that uses this event MUST have a unique @Key@,--- otherwise the event may not be reliably called!-onCreated :: action -> Attribute action-onCreated action =- E $ \sink n -> do- cb <- callbackToJSVal =<< asyncCallback (liftIO (sink action))- set "onCreated" cb n- registerCallback cb---- | @onDestroyed action@ is an event that gets called after the DOM element--- is removed from the DOM. The @action@ is given the DOM element that was--- removed from the DOM tree.------ Important note: Any node that uses this event MUST have a unique @Key@,--- otherwise the event may not be reliably called!-onDestroyed :: action -> Attribute action-onDestroyed action =- E $ \sink n -> do- cb <- callbackToJSVal =<< asyncCallback (liftIO (sink action))- set "onDestroyed" cb n- registerCallback cb---- | @onBeforeDestroyed action@ is an event that gets called before the DOM element--- is removed from the DOM. The @action@ is given the DOM element that was--- removed from the DOM tree.------ Important note: Any node that uses this event MUST have a unique @Key@,--- otherwise the event may not be reliably called!-onBeforeDestroyed :: action -> Attribute action-onBeforeDestroyed action =- E $ \sink n -> do- cb <- callbackToJSVal =<< asyncCallback (liftIO (sink action))- set "onBeforeDestroyed" cb n- registerCallback cb---- | @style_ attrs@ is an attribute that will set the @style@--- attribute of the associated DOM node to @attrs@.------ @style@ attributes not contained in @attrs@ will be deleted.------ > import qualified Data.Map as M--- > div_ [ style_ $ M.singleton "background" "red" ] [ ]------ <https://developer.mozilla.org/en-US/docs/Web/CSS>----style_ :: M.Map MisoString MisoString -> Attribute action-style_ = S
+ src/Miso/Hydrate.hs view
@@ -0,0 +1,27 @@+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Hydrate+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- Functions and helpers for Virtual DOM hydration.+--+----------------------------------------------------------------------------+module Miso.Hydrate+ ( hydrate+ ) where+-----------------------------------------------------------------------------+import qualified Miso.FFI.Internal as FFI+import Miso.Types+import Miso.DSL+-----------------------------------------------------------------------------+-- | Hydration of a t'VTree'+hydrate :: LogLevel -> DOMRef -> VTree -> IO Bool+hydrate loggingLevel domRef vtree = do+ jval <- toJSVal vtree+ fromJSValUnchecked =<<+ FFI.hydrate (loggingLevel `elem` [DebugHydrate, DebugAll]) domRef jval+-----------------------------------------------------------------------------
− src/Miso/JSBits.hs
@@ -1,1 +0,0 @@-module Miso.JSBits where
+ src/Miso/JSON.hs view
@@ -0,0 +1,831 @@+-----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ScopedTypeVariables #-}+#if __GLASGOW_HASKELL__ <= 865+{-# LANGUAGE UndecidableInstances #-}+#endif+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# OPTIONS_GHC -Wno-orphans #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.JSON+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- A JSON library specialized to MisoString for performance. Largely based+-- on [microaeson](https://hackage-content.haskell.org/package/microaeson).+--+-- Uses JS runtime primitives `JSON.stringify()` and `JSON.parse()`. +--+----------------------------------------------------------------------------+module Miso.JSON+ ( -- * JSON+ -- ** Core JSON types+ Value(..)+ , Object+ , Pair+ , Result (..)+ -- ** Constructors+ , (.=)+ , object+ , emptyArray+ , emptyObject+ -- ** Accessors+ , (.:)+ , (.:?)+ , (.:!)+ , (.!=)+ -- * Encoding and decoding+ , encode+ , encodePure+ , decode+ , Parser.decodePure+ -- * Prism-style parsers+ , withObject+ , withText+ , withArray+ , withNumber+ , withBool+ -- * Type conversion+ , FromJSON(parseJSON)+ , Parser (..)+ , parseMaybe+ , ToJSON(toJSON)+ -- * Misc.+ , fromJSON+ , parseEither+ , eitherDecode+ , typeMismatch+ -- * Pretty+ , encodePretty+ , encodePretty'+ , defConfig+ , Config (..)+ -- * FFI+ , fromJSVal_Value+ , toJSVal_Value+ , jsonStringify+ , jsonParse+ -- * Options+ , Options (..)+ , defaultOptions+ -- * Generics+ , GToJSON (..)+ , genericToJSON+ , GFromJSON (..)+ , genericParseJSON+ -- * Modifiers+ , camelTo2+ ) where+----------------------------------------------------------------------------+#ifdef GHCJS_BOTH+import qualified GHCJS.Marshal as Marshal+#endif+----------------------------------------------------------------------------+import Control.Applicative+import Control.Monad+#if __GLASGOW_HASKELL__ <= 865+import Control.Monad.Fail+import GHC.Natural (Natural)+#endif+import Data.Char+import qualified Data.Map.Strict as M+import Data.Map.Strict (Map)+import Data.Int+import GHC.Natural (naturalToInteger, naturalFromInteger)+import GHC.TypeLits+import Data.Kind+#ifndef VANILLA+import qualified Data.Text as T+#endif+import qualified Data.Text.Lazy as LT+import Data.Word+import GHC.Generics+----------------------------------------------------------------------------+import Miso.DSL.FFI+import Miso.String (FromMisoString, ToMisoString, MisoString, ms, singleton, pack)+import qualified Miso.String as MS+import Miso.JSON.Types+import qualified Miso.JSON.Parser as Parser+----------------------------------------------------------------------------+#ifndef VANILLA+import Control.Monad.Trans.Maybe+import System.IO.Unsafe (unsafePerformIO)+#else+import Numeric (showHex)+#endif++----------------------------------------------------------------------------+infixr 8 .=+(.=) :: ToJSON v => MisoString -> v -> Pair+k .= v = (k, toJSON v)+----------------------------------------------------------------------------+-- | Create a 'Value' from a list of name\/value 'Pair's.+object :: [Pair] -> Value+object = Object . M.fromList+----------------------------------------------------------------------------+-- | The empty JSON 'Object' (i.e. @{}@).+emptyObject :: Value+emptyObject = Object mempty+----------------------------------------------------------------------------+-- | The empty JSON 'Array' (i.e. @[]@).+emptyArray :: Value+emptyArray = Array mempty+----------------------------------------------------------------------------+(.:) :: FromJSON a => Object -> MisoString -> Parser a+m .: k = maybe (pfail ("Key not found: " <> k)) parseJSON (M.lookup k m)+----------------------------------------------------------------------------+(.:?) :: FromJSON a => Object -> MisoString -> Parser (Maybe a)+m .:? k = maybe (pure Nothing) parseJSON (M.lookup k m)+----------------------------------------------------------------------------+(.:!) :: FromJSON a => Object -> MisoString -> Parser (Maybe a)+m .:! k = maybe (pure Nothing) (fmap Just . parseJSON) (M.lookup k m)+----------------------------------------------------------------------------+(.!=) :: Parser (Maybe a) -> a -> Parser a+mv .!= def = fmap (maybe def id) mv+----------------------------------------------------------------------------+class ToJSON a where+ toJSON :: a -> Value+ default toJSON :: (Generic a, GToJSON (Rep a)) => a -> Value+ toJSON = genericToJSON defaultOptions+----------------------------------------------------------------------------+genericToJSON :: (Generic a, GToJSON (Rep a)) => Options -> a -> Value+genericToJSON opts = object . gToJSON opts [] . from+----------------------------------------------------------------------------+data Options+ = Options+ { fieldLabelModifier :: String -> String+ }+----------------------------------------------------------------------------+defaultOptions :: Options+defaultOptions = Options { fieldLabelModifier = \x -> x }+----------------------------------------------------------------------------+camelTo2 :: Char -> String -> String+camelTo2 c = Prelude.map toLower . go2 . go1+ where go1 "" = ""+ go1 (x:u:l:xs) | isUpper u && isLower l = x : c : u : l : go1 xs+ go1 (x:xs) = x : go1 xs+ go2 "" = ""+ go2 (l:u:xs) | isLower l && isUpper u = l : c : u : go2 xs+ go2 (x:xs) = x : go2 xs+----------------------------------------------------------------------------+class GToJSON (f :: Type -> Type) where+ gToJSON :: Options -> [Pair] -> f a -> [Pair]+----------------------------------------------------------------------------+instance GToJSON a => GToJSON (D1 i a) where+ gToJSON opts acc (M1 x) = gToJSON opts acc x+----------------------------------------------------------------------------+instance GToJSON a => GToJSON (C1 i a) where+ gToJSON opts acc (M1 x) = gToJSON opts acc x+----------------------------------------------------------------------------+instance (GToJSON a, GToJSON b) => GToJSON (a :*: b) where+ gToJSON opts acc (x :*: y) = gToJSON opts acc x <> gToJSON opts acc y+----------------------------------------------------------------------------+instance (TypeError ('Text "Sum types unsupported"), GToJSON a, GToJSON b) => GToJSON (a :+: b) where+ gToJSON opts acc = \case+ L1 x -> gToJSON opts acc x+ R1 x -> gToJSON opts acc x+----------------------------------------------------------------------------+instance GToJSON U1 where+ gToJSON _ acc U1 = acc+----------------------------------------------------------------------------+instance GToJSON V1 where+ gToJSON _ acc _ = acc+----------------------------------------------------------------------------+instance (Selector s, ToJSON a) => GToJSON (S1 s (K1 i a)) where+ gToJSON opts acc (M1 (K1 x)) = ms field .= toJSON x : acc+ where+ field :: String+ field = fieldLabelModifier opts $ selName (undefined :: S1 s (K1 i a) ())+----------------------------------------------------------------------------+instance ToJSON () where+ toJSON () = Array []+----------------------------------------------------------------------------+instance ToJSON Value where+ toJSON = id+----------------------------------------------------------------------------+instance ToJSON Char where+ toJSON c = String (singleton c)+----------------------------------------------------------------------------+instance ToJSON Bool where+ toJSON = Bool+----------------------------------------------------------------------------+instance {-# OVERLAPPING #-} ToJSON String where+ toJSON = toJSON . MS.pack+----------------------------------------------------------------------------+instance {-# OVERLAPPABLE #-} ToJSON a => ToJSON [a] where+ toJSON = Array . Prelude.map toJSON+----------------------------------------------------------------------------+instance ToJSON v => ToJSON (M.Map MisoString v) where+ toJSON = Object . M.map toJSON+----------------------------------------------------------------------------+instance ToJSON a => ToJSON (Maybe a) where+ toJSON = \case+ Nothing -> Null+ Just a -> toJSON a+----------------------------------------------------------------------------+instance (ToJSON a,ToJSON b) => ToJSON (a,b) where+ toJSON (a,b) = Array [toJSON a, toJSON b]+----------------------------------------------------------------------------+instance (ToJSON a,ToJSON b,ToJSON c) => ToJSON (a,b,c) where+ toJSON (a,b,c) = Array [toJSON a, toJSON b, toJSON c]+----------------------------------------------------------------------------+instance (ToJSON a,ToJSON b,ToJSON c, ToJSON d) => ToJSON (a,b,c,d) where+ toJSON (a,b,c,d) = Array [toJSON a, toJSON b, toJSON c, toJSON d]+----------------------------------------------------------------------------+instance ToJSON MisoString where+ toJSON = String+----------------------------------------------------------------------------+#ifndef VANILLA+instance ToJSON T.Text where+ toJSON = toJSON . ms+#endif+----------------------------------------------------------------------------+instance ToJSON LT.Text where+ toJSON = toJSON . ms+----------------------------------------------------------------------------+instance ToJSON Float where+ toJSON = Number . realToFrac+----------------------------------------------------------------------------+instance ToJSON Double where+ toJSON = Number+----------------------------------------------------------------------------+instance ToJSON Int where toJSON = Number . realToFrac+instance ToJSON Int8 where toJSON = Number . realToFrac+instance ToJSON Int16 where toJSON = Number . realToFrac+instance ToJSON Int32 where toJSON = Number . realToFrac+----------------------------------------------------------------------------+instance ToJSON Word where toJSON = Number . realToFrac+instance ToJSON Word8 where toJSON = Number . realToFrac+instance ToJSON Word16 where toJSON = Number . realToFrac+instance ToJSON Word32 where toJSON = Number . realToFrac+----------------------------------------------------------------------------+-- | Possibly lossy due to conversion to 'Double'+instance ToJSON Int64 where toJSON = Number . realToFrac+----------------------------------------------------------------------------+-- | Possibly lossy due to conversion to 'Double'+instance ToJSON Word64 where toJSON = Number . realToFrac+----------------------------------------------------------------------------+-- | Possibly lossy due to conversion to 'Double'+instance ToJSON Integer where toJSON = Number . fromInteger+----------------------------------------------------------------------------+-- | Possibly lossy due to conversion to 'Double'+instance ToJSON Natural where toJSON = Number . fromInteger . naturalToInteger+----------------------------------------------------------------------------+newtype Parser a = Parser { unParser :: Either MisoString a }+ deriving (Functor, Applicative, Monad)+----------------------------------------------------------------------------+instance MonadFail Parser where+ fail = pfail . pack+----------------------------------------------------------------------------+instance Alternative Parser where+ empty = Parser (Left mempty)+ Parser (Left _) <|> r = r+ l <|> _ = l+----------------------------------------------------------------------------+instance MonadPlus Parser+----------------------------------------------------------------------------+parseMaybe :: (a -> Parser b) -> a -> Maybe b+parseMaybe m v =+ case parseEither m v of+ Left _ -> Nothing+ Right r -> Just r +----------------------------------------------------------------------------+parseEither :: (a -> Parser b) -> a -> Either MisoString b+parseEither m v = unParser (m v)+----------------------------------------------------------------------------+pfail :: MisoString -> Parser a+pfail message = Parser (Left message)+----------------------------------------------------------------------------+class FromJSON a where+ parseJSON :: Value -> Parser a+ default parseJSON :: (Generic a, GFromJSON (Rep a)) => Value -> Parser a+ parseJSON = genericParseJSON defaultOptions+----------------------------------------------------------------------------+class GFromJSON (f :: Type -> Type) where+ gParseJSON :: Options -> Value -> Parser (f a)+----------------------------------------------------------------------------+genericParseJSON :: (Generic a, GFromJSON (Rep a)) => Options -> Value -> Parser a+genericParseJSON opts value = to <$> gParseJSON opts value+----------------------------------------------------------------------------+instance GFromJSON a => GFromJSON (D1 i a) where+ gParseJSON opts x = M1 <$> gParseJSON opts x+----------------------------------------------------------------------------+instance GFromJSON a => GFromJSON (C1 i a) where+ gParseJSON opts x = M1 <$> gParseJSON opts x+----------------------------------------------------------------------------+instance (GFromJSON a, GFromJSON b) => GFromJSON (a :*: b) where+ gParseJSON opts x = (:*:) <$> gParseJSON opts x <*> gParseJSON opts x+----------------------------------------------------------------------------+instance (TypeError ('Text "Sum types unsupported"), GFromJSON a, GFromJSON b) => GFromJSON (a :+: b) where+ gParseJSON opts x = (L1 <$> gParseJSON opts x) <|> (R1 <$> gParseJSON opts x)+----------------------------------------------------------------------------+instance GFromJSON U1 where+ gParseJSON _ _ = pure U1+----------------------------------------------------------------------------+instance {-# OVERLAPPABLE #-} (Selector s, FromJSON a) => GFromJSON (S1 s (K1 i a)) where+ gParseJSON opts = \case+ Object o ->+ M1 . K1 <$> o .: ms field+ v ->+ M1 . K1 <$> parseJSON v+ where+ field = fieldLabelModifier opts $ selName (undefined :: S1 s (K1 i a) ())+----------------------------------------------------------------------------+instance {-# OVERLAPPING #-} (Selector s, FromJSON a) => GFromJSON (S1 s (K1 i (Maybe a))) where+ gParseJSON opts = \case+ Object o ->+ M1 . K1 <$> o .:? ms field+ v ->+ M1 . K1 <$> parseJSON v+ where+ field = fieldLabelModifier opts $ selName (undefined :: S1 s (K1 i (Maybe a)) ())+----------------------------------------------------------------------------+instance FromJSON Value where+ parseJSON = pure+----------------------------------------------------------------------------+instance FromJSON Bool where+ parseJSON = withBool "Bool" pure+----------------------------------------------------------------------------+instance FromJSON MisoString where+ parseJSON = withText "MisoString" pure+----------------------------------------------------------------------------+#ifndef VANILLA+instance FromJSON T.Text where+ parseJSON = withText "Text" go+ where+ go s =+ case MS.fromMisoStringEither s of+ Right lt -> pure lt+ Left e -> pfail $ ms e+#endif+----------------------------------------------------------------------------+instance FromJSON LT.Text where+ parseJSON = withText "LText" go+ where+ go s =+ case MS.fromMisoStringEither s of+ Right lt -> pure lt+ Left e -> pfail $ ms e+----------------------------------------------------------------------------+instance {-# OVERLAPPING #-} FromJSON String where+ parseJSON = withText "String" (pure . MS.unpack)+----------------------------------------------------------------------------+instance {-# OVERLAPPABLE #-} FromJSON a => FromJSON [a] where+ parseJSON = withArray "[a]" (mapM parseJSON)+----------------------------------------------------------------------------+instance FromJSON Double where+ parseJSON Null = pure (0/0)+ parseJSON j = withNumber "Double" pure j+----------------------------------------------------------------------------+instance FromJSON Float where+ parseJSON Null = pure (0/0)+ parseJSON j = withNumber "Float" (pure . realToFrac) j+----------------------------------------------------------------------------+instance FromJSON Integer where+ parseJSON = withNumber "Integer" (pure . round)+----------------------------------------------------------------------------+instance FromJSON Natural where+ parseJSON = withNumber "Natural" parseNumber+ where parseNumber d | d < 0 = pfail ("Cannot parse negative number as Natural: " <> ms d)+ | isNaN d = pfail ("Cannot parse NaN as Natural: " <> ms d)+ | otherwise = pure $ naturalFromInteger $ fromInteger $ round d +----------------------------------------------------------------------------+instance FromJSON Int where+ parseJSON = withNumber "Int" (pure . fromInteger . round)+----------------------------------------------------------------------------+instance FromJSON Int8 where+ parseJSON = withNumber "Int8" (pure . fromInteger . round)+----------------------------------------------------------------------------+instance FromJSON Int16 where+ parseJSON = withNumber "Int16" (pure . fromInteger . round)+----------------------------------------------------------------------------+instance FromJSON Int32 where+ parseJSON = withNumber "Int32" (pure . fromInteger . round)+----------------------------------------------------------------------------+instance FromJSON Int64 where+ parseJSON = withNumber "Int64" (pure . fromInteger . round)+----------------------------------------------------------------------------+instance FromJSON Word where+ parseJSON = withNumber "Word" (pure . fromInteger . round)+----------------------------------------------------------------------------+instance FromJSON Word8 where+ parseJSON = withNumber "Word8" (pure . fromInteger . round)+----------------------------------------------------------------------------+instance FromJSON Word16 where+ parseJSON = withNumber "Word16" (pure . fromInteger . round)+----------------------------------------------------------------------------+instance FromJSON Word32 where+ parseJSON = withNumber "Word32" (pure . fromInteger . round)+----------------------------------------------------------------------------+instance FromJSON Word64 where+ parseJSON = withNumber "Word64" (pure . fromInteger . round)+----------------------------------------------------------------------------+instance FromJSON () where+ parseJSON = withArray "()" $ \lst ->+ case lst of+ [] -> pure ()+ _ -> pfail "expected ()"+----------------------------------------------------------------------------+instance (FromJSON a, FromJSON b) => FromJSON (a,b) where+ parseJSON = withArray "(a,b)" $ \lst ->+ case lst of+ [a,b] -> liftM2 (,) (parseJSON a) (parseJSON b)+ _ -> pfail "expected (a,b)"+----------------------------------------------------------------------------+instance (FromJSON a, FromJSON b, FromJSON c) => FromJSON (a,b,c) where+ parseJSON = withArray "(a,b,c)" $ \lst ->+ case lst of+ [a,b,c] -> liftM3 (,,) (parseJSON a) (parseJSON b) (parseJSON c)+ _ -> pfail "expected (a,b,c)"+----------------------------------------------------------------------------+instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d) => FromJSON (a,b,c,d) where+ parseJSON = withArray "(a,b,c,d)" $ \lst ->+ case lst of+ [a,b,c,d] -> liftM4 (,,,) (parseJSON a) (parseJSON b) (parseJSON c) (parseJSON d)+ _ -> pfail "expected (a,b,c,d)"+----------------------------------------------------------------------------+instance FromJSON a => FromJSON (Maybe a) where+ parseJSON Null = pure Nothing+ parseJSON j = Just <$> parseJSON j+----------------------------------------------------------------------------+instance FromJSON Ordering where+ parseJSON = withText "{'LT','EQ','GT'}" $ \s ->+ case s of+ "LT" -> pure LT+ "EQ" -> pure EQ+ "GT" -> pure GT+ _ -> pfail "expected {'LT','EQ','GT'}"+----------------------------------------------------------------------------+instance FromJSON Char where+ parseJSON = withText "Char" $ \xs ->+ case xs of+ x | MS.length x == 1 -> pure (MS.head x)+ | otherwise -> pfail ("expected Char, received: " <> x)+----------------------------------------------------------------------------+instance FromJSON v => FromJSON (Map MisoString v) where+ parseJSON = withObject "FromJSON v => Map MisoString v" $ mapM parseJSON+----------------------------------------------------------------------------+withBool :: MisoString -> (Bool -> Parser a) -> Value -> Parser a+withBool _ f (Bool arr) = f arr+withBool expected _ v = typeMismatch expected v+----------------------------------------------------------------------------+withText :: MisoString -> (MisoString -> Parser a) -> Value -> Parser a+withText _ f (String txt) = f txt+withText expected _ v = typeMismatch expected v+----------------------------------------------------------------------------+withArray :: MisoString -> ([Value] -> Parser a) -> Value -> Parser a+withArray _ f (Array lst) = f lst+withArray expected _ v = typeMismatch expected v+----------------------------------------------------------------------------+withObject :: MisoString -> (Object -> Parser a) -> Value -> Parser a+withObject _ f (Object obj) = f obj+withObject expected _ v = typeMismatch expected v+----------------------------------------------------------------------------+withNumber :: MisoString -> (Double -> Parser a) -> Value -> Parser a+withNumber _ f (Number n) = f n+withNumber expected _ v = typeMismatch expected v+----------------------------------------------------------------------------+typeMismatch :: MisoString -> Value -> Parser a+typeMismatch expected actual =+ pfail+ ( "typeMismatch: Expected " <> expected <> " but encountered " <> case actual of+ Object _ -> "Object"+ Array _ -> "Array"+ String _ -> "String"+ Number _ -> "Number"+ Bool _ -> "Boolean"+ Null -> "Null"+ )+----------------------------------------------------------------------------+#ifdef VANILLA+encode :: ToJSON a => a -> MisoString+encode = encodePure+#else+encode :: ToJSON a => a -> MisoString+encode x = unsafePerformIO $ jsonStringify =<< toJSVal_Value (toJSON x)+#endif+----------------------------------------------------------------------------+-- | Relies on the pure implementation of JSON parsing / serialization.+--+-- This can be used on the server or the client, it is more efficient to+-- use 'encode' on the client (since it relies on @JSON.stringify()@).+--+encodePure :: ToJSON a => a -> MisoString+encodePure = ms . toJSON+----------------------------------------------------------------------------+instance FromMisoString Value where+ fromMisoStringEither = Parser.decodePure+----------------------------------------------------------------------------+#ifdef VANILLA+-- | Escape special characters in a string for JSON serialization+-- Handles: \, ", and all JSON control characters per RFC 8259+escapeJSONString :: MisoString -> MisoString+escapeJSONString = MS.concatMap escapeChar+ where+ escapeChar :: Char -> MisoString+ escapeChar '\\' = "\\\\" -- Backslash+ escapeChar '"' = "\\\"" -- Double quote+ escapeChar '\b' = "\\b" -- Backspace+ escapeChar '\f' = "\\f" -- Form feed+ escapeChar '\n' = "\\n" -- Newline+ escapeChar '\r' = "\\r" -- Carriage return+ escapeChar '\t' = "\\t" -- Tab+ escapeChar c+ | isControl c = ms ("\\u" <> padHex (ord c)) -- Other control chars as \uXXXX+ | otherwise = singleton c++ padHex :: Int -> MisoString+ padHex n = MS.pack $ replicate (4 - length h) '0' ++ h+ where h = showHex n ""+----------------------------------------------------------------------------+#endif+instance ToMisoString Value where+ toMisoString = \case+ String s ->+#ifdef VANILLA+ "\"" <> escapeJSONString s <> "\""+#else+ "\"" <> s <> "\""+#endif+ Number n ->+ ms n+ Null ->+ "null"+ Array xs ->+ "[" <> MS.intercalate "," (fmap ms xs) <> "]"+ Bool True ->+ "true"+ Bool False ->+ "false"+ Object o ->+ "{" <>+#ifdef VANILLA+ MS.intercalate "," [ "\"" <> escapeJSONString k <> "\"" <> ":" <> ms v | (k,v) <- M.toList o ]+#else+ MS.intercalate "," [ "\"" <> k <> "\"" <> ":" <> ms v | (k,v) <- M.toList o ]+#endif+ <> "}"+----------------------------------------------------------------------------+#ifdef VANILLA+decode :: FromJSON a => MisoString -> Maybe a+decode s+ | Right x <- Parser.decodePure s+ , Success v <- fromJSON x = v+ | otherwise = Nothing+#else+decode :: FromJSON a => MisoString -> Maybe a+decode s+ | Right x <- eitherDecode s = Just x+ | otherwise = Nothing+#endif+-----------------------------------------------------------------------------+#ifdef GHCJS_OLD+foreign import javascript unsafe+ "$r = JSON.stringify($1, null, $2)"+ encodePretty_ffi :: JSVal -> Int -> IO MisoString+#endif+-----------------------------------------------------------------------------+#ifdef GHCJS_NEW+foreign import javascript unsafe+ "(($1) => { return JSON.stringify($1, null, $2); })"+ encodePretty_ffi :: JSVal -> Int -> IO MisoString+#endif+-----------------------------------------------------------------------------+#ifdef WASM+foreign import javascript unsafe+ "return JSON.stringify($1, null, $2);"+ encodePretty_ffi :: JSVal -> Int -> IO MisoString+#endif+-----------------------------------------------------------------------------+#ifdef VANILLA+encodePretty' :: ToJSON a => Config -> a -> MisoString+encodePretty' = error "encodePretty': not implemented"+-----------------------------------------------------------------------------+encodePretty :: ToJSON a => a -> MisoString+encodePretty _ = error "encodePretty: not implemented"+-----------------------------------------------------------------------------+#else+-----------------------------------------------------------------------------+encodePretty' :: ToJSON a => Config -> a -> MisoString+encodePretty' (Config s) x = unsafePerformIO (flip encodePretty_ffi s =<< toJSVal_Value (toJSON x))+-----------------------------------------------------------------------------+encodePretty :: ToJSON a => a -> MisoString+encodePretty = encodePretty' defConfig+#endif+-----------------------------------------------------------------------------+newtype Config+ = Config+ { spaces :: Int+ } deriving (Show, Eq)+-----------------------------------------------------------------------------+defConfig :: Config+defConfig = Config 4+-----------------------------------------------------------------------------+#ifdef GHCJS_OLD+foreign import javascript unsafe+ "$r = JSON.stringify($1)"+ jsonStringify :: JSVal -> IO MisoString+#endif+-----------------------------------------------------------------------------+#ifdef GHCJS_NEW+foreign import javascript unsafe+ "(($1) => { return JSON.stringify($1); })"+ jsonStringify :: JSVal -> IO MisoString+#endif+-----------------------------------------------------------------------------+#ifdef WASM+foreign import javascript unsafe+ "return JSON.stringify($1);"+ jsonStringify :: JSVal -> IO MisoString+#endif+-----------------------------------------------------------------------------+#ifdef VANILLA+jsonStringify :: JSVal -> IO MisoString+jsonStringify _ = error "jsonStringify: not implemented"+#endif+-----------------------------------------------------------------------------+#ifdef GHCJS_OLD+foreign import javascript unsafe+ "$r = JSON.parse($1)"+ jsonParse :: MisoString -> IO JSVal+#endif+-----------------------------------------------------------------------------+#ifdef GHCJS_NEW+foreign import javascript unsafe+ "(($1) => { return JSON.parse($1); })"+ jsonParse :: MisoString -> IO JSVal+#endif+-----------------------------------------------------------------------------+#ifdef WASM+foreign import javascript unsafe+ "return JSON.parse($1);"+ jsonParse :: MisoString -> IO JSVal+#endif+-----------------------------------------------------------------------------+#ifdef VANILLA+jsonParse :: MisoString -> IO JSVal+jsonParse _ = error "jsonParse: not implemented"+#endif+-----------------------------------------------------------------------------+#ifdef VANILLA+eitherDecode :: FromJSON a => MisoString -> Either MisoString a+eitherDecode string =+ case Parser.decodePure string of+ Left s ->+ Left (pack s)+ Right v ->+ parseEither parseJSON v+#else+eitherDecode :: FromJSON a => MisoString -> Either MisoString a+eitherDecode string = unsafePerformIO $ do+ (jsonParse string >>= fromJSVal_Value) >>= \case+ Nothing ->+ pure $ Left ("eitherDecode: " <> string)+ Just result ->+ pure (case fromJSON result of+ Success x -> Right x+ Error err -> Left err)+#endif+----------------------------------------------------------------------------+fromJSON :: FromJSON a => Value -> Result a+fromJSON value =+ case parseEither parseJSON value of+ Left s -> Error s+ Right x -> Success x+----------------------------------------------------------------------------+#ifdef GHCJS_BOTH+toJSVal_Value :: Value -> IO JSVal+toJSVal_Value = \case+ Null ->+ pure jsNull+ Bool bool_ ->+ Marshal.toJSVal bool_+ String string ->+ Marshal.toJSVal string+ Number double ->+ Marshal.toJSVal double+ Array arr ->+ toJSVal_List =<< mapM toJSVal_Value arr+ Object hms -> do+ o <- create_ffi+ forM_ (M.toList hms) $ \(k,v) -> do+ v' <- toJSVal_Value v+ setProp_ffi k v' o+ pure o+#endif+-----------------------------------------------------------------------------+#ifdef GHCJS_BOTH+fromJSVal_Value :: JSVal -> IO (Maybe Value)+fromJSVal_Value jsval_ = do+ typeof jsval_ >>= \case+ 0 -> return (Just Null)+ 1 -> Just . Number <$> Marshal.fromJSValUnchecked jsval_+ 2 -> Just . String <$> Marshal.fromJSValUnchecked jsval_+ 3 -> fromJSValUnchecked_Int jsval_ >>= \case+ 0 -> pure $ Just (Bool False)+ 1 -> pure $ Just (Bool True)+ _ -> pure Nothing+ 4 -> do xs <- Marshal.fromJSValUnchecked jsval_+ values <- forM xs fromJSVal_Value+ pure (Array <$> sequence values)+ 5 -> do keys <- Marshal.fromJSValUnchecked =<< listProps_ffi jsval_+ result <-+ runMaybeT $ forM keys $ \k -> do+ key <- MaybeT (Marshal.fromJSVal k)+ raw <- MaybeT $ Just <$> getProp_ffi key jsval_+ value <- MaybeT (fromJSVal_Value raw)+ pure (key, value)+ pure (toObject <$> result)+ _ -> error "fromJSVal_Value: Unknown JSON type"+ where+ toObject = Object . M.fromList+#endif+-----------------------------------------------------------------------------+#ifdef WASM+fromJSVal_Value :: JSVal -> IO (Maybe Value)+fromJSVal_Value jsval = do+ typeof jsval >>= \case+ 0 -> return (Just Null)+ 1 -> Just . Number <$> fromJSValUnchecked_Double jsval+ 2 -> pure $ Just $ String $ (JSString jsval)+ 3 -> fromJSValUnchecked_Int jsval >>= \case+ 0 -> pure $ Just (Bool False)+ 1 -> pure $ Just (Bool True)+ _ -> pure Nothing+ 4 -> do xs <- fromJSValUnchecked_List jsval+ values <- forM xs fromJSVal_Value+ pure (Array <$> sequence values)+ 5 -> do keys <- fromJSValUnchecked_List =<< listProps_ffi jsval+ result <-+ runMaybeT $ forM keys $ \k -> do+ let key = JSString k+ raw <- MaybeT $ Just <$> getProp_ffi key jsval+ value <- MaybeT (fromJSVal_Value raw)+ pure (key, value)+ pure (toObject <$> result)+ _ -> error "fromJSVal_Value: Unknown JSON type"+ where+ toObject = Object . M.fromList+#endif+-----------------------------------------------------------------------------+#ifdef VANILLA+-----------------------------------------------------------------------------+fromJSVal_Value :: JSVal -> IO (Maybe Value)+fromJSVal_Value = error "fromJSVal_Value: not implemented"+-----------------------------------------------------------------------------+toJSVal_Value :: Value -> IO JSVal+toJSVal_Value = error "toJSVal_Value: not implemented"+-----------------------------------------------------------------------------+#endif+-----------------------------------------------------------------------------+#ifdef GHCJS_NEW+foreign import javascript unsafe+ "(($1) => { return globalThis.miso.typeOf($1); })"+ typeof :: JSVal -> IO Int+#endif+-----------------------------------------------------------------------------+#ifdef WASM+foreign import javascript unsafe+ "return globalThis.miso.typeOf($1);"+ typeof :: JSVal -> IO Int+#endif+-----------------------------------------------------------------------------+#ifdef GHCJS_OLD+foreign import javascript unsafe+ "$r = globalThis.miso.typeOf($1);"+ typeof :: JSVal -> IO Int+#endif+-----------------------------------------------------------------------------+#ifdef WASM+toJSVal_Value :: Value -> IO JSVal+toJSVal_Value = \case+ Null ->+ pure jsNull+ Bool bool_ ->+ toJSVal_Bool bool_+ String string ->+ toJSVal_JSString string+ Number double ->+ toJSVal_Double double+ Array arr ->+ toJSVal_List =<< mapM toJSVal_Value arr+ Object hms -> do+ o <- create_ffi+ forM_ (M.toList hms) $ \(k,v) -> do+ v' <- toJSVal_Value v+ setProp_ffi k v' o+ pure o+#endif+-----------------------------------------------------------------------------
+ src/Miso/JSON/Lexer.hs view
@@ -0,0 +1,109 @@+----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.JSON.Lexer+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- A Lexer for the JSON specification. Meant to be used on the server w/ SSR.+--+-- This was ported from <https://github.com/dmjio/json-test> by [@ners](https://github.com/ners)+-- +----------------------------------------------------------------------------+module Miso.JSON.Lexer (Token (..), tokens) where+----------------------------------------------------------------------------+import Control.Applicative (optional, Alternative (some, many))+import Data.Char (isHexDigit, chr, isSpace)+import Data.Foldable (Foldable (fold))+import Data.Functor (void)+import Data.Ix (Ix (inRange))+import Data.Maybe (catMaybes, listToMaybe)+import Numeric (readHex)+import Prelude hiding (null)+----------------------------------------------------------------------------+import Miso.String (fromMisoString, ToMisoString (toMisoString), MisoString)+import Miso.Util (oneOf)+import Miso.Util.Lexer hiding (string', token)+----------------------------------------------------------------------------+#if __GLASGOW_HASKELL__ <= 881+import Control.Applicative (liftA2)+#endif+----------------------------------------------------------------------------+data Token+ = TokenPunctuator Char+ | TokenNumber Double+ | TokenBool Bool+ | TokenString MisoString+ | TokenNull+ deriving (Eq, Show)+----------------------------------------------------------------------------+number :: Lexer Double+number = fromMisoString . fold . catMaybes <$> sequence+ [ optional $ string "-"+ , Just <$> int+ , optional $ liftA2 (<>) (string ".") int+ , optional $ liftA2 (<>) (oneOf $ string <$> ["e", "e+", "e-", "E", "E+", "E-"]) int+ ] where+ digit = satisfy $ inRange ('0', '9')+ int = toMisoString <$> some digit+----------------------------------------------------------------------------+bool :: Lexer Bool+bool = oneOf+ [ False <$ string "false"+ , True <$ string "true"+ ]+----------------------------------------------------------------------------+string' :: Lexer MisoString+string' = char '"' *> (toMisoString <$> many character) <* char '"'+ where+ character = oneOf+ [ satisfy $ \c -> c /= '"' && c /= '\\'+ , escapedCharacter+ ]+ hexDigit = satisfy isHexDigit+ escapedCharacter = char '\\' *> oneOf+ [ char '"'+ , char '\\'+ , char '/'+ , '\b' <$ char 'b'+ , '\f' <$ char 'f'+ , '\n' <$ char 'n'+ , '\r' <$ char 'r'+ , '\t' <$ char 't'+ , do+ a <- hexDigit+ b <- hexDigit+ c <- hexDigit+ d <- hexDigit+ maybe oops (pure . chr . fst)+ . listToMaybe+ . readHex+ $ [a, b, c, d]+ ]+----------------------------------------------------------------------------+null :: Lexer ()+null = void (string "null")+----------------------------------------------------------------------------+punctuator :: Lexer Char+punctuator = oneOf (char <$> "[]{},:")+----------------------------------------------------------------------------+whitespace :: Lexer ()+whitespace = void (satisfy isSpace)+----------------------------------------------------------------------------+token :: Lexer Token+token = oneOf+ [ TokenPunctuator <$> punctuator+ , TokenNumber <$> number+ , TokenBool <$> bool+ , TokenString <$> string'+ , TokenNull <$ null+ ]+----------------------------------------------------------------------------+tokens :: Lexer [Token]+tokens = some (many whitespace *> token)+----------------------------------------------------------------------------
+ src/Miso/JSON/Parser.hs view
@@ -0,0 +1,83 @@+----------------------------------------------------------------------------+{-# LANGUAGE LambdaCase #-}+----------------------------------------------------------------------------+-- |+-- Module : Miso.JSON.Parser+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- A Parser for the JSON specification. Meant to be used on the server w/ SSR.+--+-- This was ported from <https://github.com/dmjio/json-test> by [@ners](https://github.com/ners)+-- +----------------------------------------------------------------------------+module Miso.JSON.Parser (decodePure) where+----------------------------------------------------------------------------+import Data.Bifunctor (Bifunctor(first))+import Data.Functor (void)+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as Map+import Prelude hiding (null)+----------------------------------------------------------------------------+import Miso.JSON.Types+import Miso.JSON.Lexer (Token (..), tokens)+import Miso.String (MisoString)+import Miso.Util (sepBy, oneOf)+import Miso.Util.Parser+import Miso.Util.Lexer (runLexer, mkStream)+----------------------------------------------------------------------------+number :: Parser Token Double+number = do+ TokenNumber d <- anyToken+ pure d+----------------------------------------------------------------------------+bool :: Parser Token Bool+bool = do+ TokenBool b <- anyToken+ pure b+----------------------------------------------------------------------------+string' :: Parser Token MisoString+string' = do+ TokenString s <- anyToken+ pure s+----------------------------------------------------------------------------+array :: Parser Token [Value]+array = do+ void . token_ $ TokenPunctuator '['+ values <- sepBy (token_ $ TokenPunctuator ',') value+ void . token_ $ TokenPunctuator ']'+ pure values+----------------------------------------------------------------------------+object :: Parser Token (Map MisoString Value)+object = do+ void . token_ $ TokenPunctuator '{'+ fields <- sepBy (token_ $ TokenPunctuator ',') $ do+ key <- string'+ void . token_ $ TokenPunctuator ':'+ val <- value+ pure (key, val)+ void . token_ $ TokenPunctuator '}'+ pure $ Map.fromList fields+----------------------------------------------------------------------------+null :: Parser Token ()+null = void $ token_ TokenNull+----------------------------------------------------------------------------+value :: Parser Token Value+value = oneOf+ [ Number <$> number+ , Bool <$> bool+ , String <$> string'+ , Array <$> array+ , Object <$> object+ , Null <$ null+ ]+----------------------------------------------------------------------------+decodePure :: MisoString -> Either String Value+decodePure = first show+ . either (Left . LexicalError) (parse value . fst)+ . runLexer tokens+ . mkStream+----------------------------------------------------------------------------
+ src/Miso/JSON/Types.hs view
@@ -0,0 +1,116 @@+-----------------------------------------------------------------------------+-- |+-- Module : Miso.JSON.Types+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- Types for the @Miso.JSON@ module and JSON specification.+--+-- This was ported from <https://github.com/dmjio/json-test> by [@ners](https://github.com/ners)+--+----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+----------------------------------------------------------------------------+module Miso.JSON.Types+ ( -- * Types+ Value (..)+ , Result (..)+ , Pair+ , Object+ ) where+----------------------------------------------------------------------------+import Control.Applicative (Alternative (..))+import Control.Monad (MonadPlus(..), ap)+import Data.Map.Strict (Map)+----------------------------------------------------------------------------+import Data.String (IsString(fromString))+import Miso.String (MisoString, toMisoString)+----------------------------------------------------------------------------+#if __GLASGOW_HASKELL__ <= 881+import Prelude hiding (fail)+import Control.Monad.Fail (MonadFail (..))+#endif+----------------------------------------------------------------------------+data Value+ = Number Double+ | Bool Bool+ | String MisoString+ | Array [Value]+ | Object (Map MisoString Value)+ | Null+ deriving (Show, Eq)+----------------------------------------------------------------------------+instance IsString Value where+ fromString = String . fromString+----------------------------------------------------------------------------+type Pair = (MisoString, Value)+----------------------------------------------------------------------------+type Object = Map MisoString Value+----------------------------------------------------------------------------+data Result a+ = Success a+ | Error MisoString+ deriving (Show, Eq)+----------------------------------------------------------------------------+instance Functor Result where+ fmap f (Success a) = Success (f a)+ fmap _ (Error err) = Error err+ {-# INLINE fmap #-}+----------------------------------------------------------------------------+instance Applicative Result where+ pure = Success+ {-# INLINE pure #-}+ (<*>) = ap+ {-# INLINE (<*>) #-}+----------------------------------------------------------------------------+instance Monad Result where+ return = pure+ {-# INLINE return #-}+ Success a >>= k = k a+ Error err >>= _ = Error err+ {-# INLINE (>>=) #-}+----------------------------------------------------------------------------+instance MonadFail Result where+ fail err = Error $ toMisoString err+ {-# INLINE fail #-}+----------------------------------------------------------------------------+instance Alternative Result where+ empty = mzero+ {-# INLINE empty #-}+ (<|>) = mplus+ {-# INLINE (<|>) #-}+----------------------------------------------------------------------------+instance MonadPlus Result where+ mzero = fail "mzero"+ {-# INLINE mzero #-}+ mplus a@(Success _) _ = a+ mplus _ b = b+ {-# INLINE mplus #-}+----------------------------------------------------------------------------+instance Semigroup (Result a) where+ (<>) = mplus+ {-# INLINE (<>) #-}+----------------------------------------------------------------------------+instance Monoid (Result a) where+ mempty = fail "mempty"+ {-# INLINE mempty #-}+ mappend = (<>)+ {-# INLINE mappend #-}+----------------------------------------------------------------------------+instance Foldable Result where+ foldMap _ (Error _) = mempty+ foldMap f (Success y) = f y+ {-# INLINE foldMap #-}+----------------------------------------------------------------------------+ foldr _ z (Error _) = z+ foldr f z (Success y) = f y z+ {-# INLINE foldr #-}+----------------------------------------------------------------------------+instance Traversable Result where+ traverse _ (Error err) = pure (Error err)+ traverse f (Success a) = Success <$> f a+ {-# INLINE traverse #-}+----------------------------------------------------------------------------
+ src/Miso/Lens.hs view
@@ -0,0 +1,897 @@+-----------------------------------------------------------------------------+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RankNTypes #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Lens+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- This modules exposes a very simple t'Miso.Lens.Lens' formulation that is compatible with other lens libraries.+--+-- For state management of miso applications, this module should meet all of your needs. It also+-- ensures a smaller payload size during compilation.+--+-- @+-- data Lens record field+-- = Lens+-- { _get :: record -> field+-- , _set :: record -> field -> record+-- }+-- @+--+-- The goal is to provide users with an out-of-the box lens experience without the large+-- dependency footprint and cognitive load. This module also aims to preserve semantics of+-- existing lens combinators using a simple formulation (not the van Laarhoven). It must be imported+-- separately (@import Miso.Lens@) and can be used with the @Effect@ Monad inside of a miso+-- application (as described below).+--+-- This module is at fixity and interface parity with @lens@ and @microlens@ and can therefore+-- be used interchangeably with them. Simply replace the @Miso.Lens@ import with @Control.Lens@.+-- For convenience we re-export the t'Miso.Lens.Lens'' synonym to ease the transition into [lens](https://hackage.haskell.org/package/lens) or [microlens](https://hackage.haskell.org/package/microlens)+--+-- For the curious reader, if you'd like more information on 'lens' and the van Laarhoven+-- formulation, we recommend the [lens](https://hackage.haskell.org/package/lens) library.+--+-- @+-- -- Person type+-- data Person = Person+-- { _name :: String+-- , _address :: Address+-- , _age :: Int+-- } deriving (Show, Eq, Generic)+--+-- -- Address type+-- newtype Address+-- = Address+-- { _zipCode :: Zip+-- } deriving (Show, Eq)+--+-- -- | Zip code type synonym+-- type Zip = String+--+-- -- | Name Lens+-- name :: Lens Person String+-- name = 'lens' _name $ \\record x -> record { _name = x }+--+-- -- | Address Lens+-- address :: Lens Person Address+-- address = 'lens' _address $ \\record x -> record { _address = x }+--+-- -- | Zip Code Lens+-- zipCode :: Lens Address Zip+-- zipCode = 'lens' _zipCode $ \\record x -> record { _zipCode = x }+--+-- -- | Lens Composition example+-- personZip :: Lens Person Zip+-- personZip = zipCode . address+--+-- -- | Person example+-- person :: Person+-- person = Person "john" (Address "90210") 33+--+-- main :: IO ()+-- main = print $ john '&' address '.~' Address "10012"+--+-- -- Person+-- -- { _name = "john"+-- -- , _age = 33+-- -- , _address = Address {_zipCode = "10012"}+-- -- }+-- @+--+-- Example usage with miso's @Effect@ @Monad@+--+-- @+-- newtype Model = Model { _value :: Int }+--+-- value :: Lens Model Int+-- value = 'lens' _value $ \\model v -> model { _value = v }+--+-- data Action = AddOne | SubtractOne+--+-- updateModel :: Action -> Effect parent Model Action+-- updateModel = \\case +-- AddOne -> value '+=' 1+-- SubtractOne -> value '-=' 1+-- @+----------------------------------------------------------------------------+module Miso.Lens+ ( -- ** Types+ Lens+ , LensCore (..)+ , Prism (..)+ -- ** Smart constructor+ , lens+ , prism+ -- ** Re-exports+ , (&)+ , (<&>)+ -- ** Lens Combinators+ , (.~)+ , (?~)+ , set+ , (%~)+ , over+ , (^.)+ , (+~)+ , (*~)+ , (//~)+ , (-~)+ , (%=)+ , (%?=)+ , modifying+ , (+=)+ , (*=)+ , (//=)+ , (-=)+ , (.=)+ , (<~)+ , (<%=)+ , (<.=)+ , (<?=)+ , (<<.=)+ , (<<%=)+ , assign+ , use+ , view+ , (?=)+ , (<>~)+ , _1+ , _2+ , _id+ , this+ -- ** Prism Combinators+ , preview+ , preuse+ , review+ , _Nothing+ , _Just+ , _Left+ , _Right+ , (^?)+ -- *** Containers+ , At (..)+ -- *** Re-exports+ , compose+ -- *** Conversion+ , Lens'+ , toVL+ , fromVL+ ) where+----------------------------------------------------------------------------+import Control.Monad.Reader (MonadReader, asks)+import Control.Monad.State (MonadState, modify, gets)+import Control.Monad.Identity (Identity(..))+import Control.Category (Category (..))+import Control.Arrow ((>>>))+import Data.Functor.Const (Const(..))+import Data.Function ((&))+import Data.Functor((<&>))+import Data.Kind (Type)+import qualified Data.Map.Strict as M+import Data.Map.Strict (Map)+import qualified Data.Set as S+import Data.Set (Set)+import qualified Data.IntMap.Strict as IM+import Data.IntMap.Strict (IntMap)+import qualified Data.IntSet as IS+import Data.IntSet (IntSet)+import Prelude hiding ((.))+----------------------------------------------------------------------------+import Miso.Util (compose)+----------------------------------------------------------------------------+-- | A t'Lens' is a generalized getter and setter.+--+-- Lenses allow both the retrieval of values from fields in a record and the+-- assignment of values to fields in a record. The power of a t'Lens' comes+-- from its ability to be composed with other lenses.+--+-- In the context of building applications with miso, the @model@ is+-- often a deeply nested product type. This makes it highly conducive+-- to t'Lens' operations (as defined below).+--+type Lens s a = LensCore a s+----------------------------------------------------------------------------+-- | t'LensCore' is an internal type used to reverse composition like+-- VL libraries do.+data LensCore field record+ = Lens+ { _get :: record -> field+ -- ^ Retrieves a field from a record+ , _set :: field -> record -> record+ -- ^ Sets a field on a record+ }+----------------------------------------------------------------------------+-- | van Laarhoven formulation, used for conversion w/ 'Miso.miso' t'Lens'.+type Lens' s a = forall (f :: Type -> Type). Functor f => (a -> f a) -> s -> f s+----------------------------------------------------------------------------+-- | Convert from 'Miso.miso' t'Lens' to van Laarhoven t'Lens''+toVL :: Lens record field -> Lens' record field+toVL Lens {..} = \f record -> flip _set record <$> f (_get record)+----------------------------------------------------------------------------+-- | Convert from 'Miso.miso' t'Lens' to van Laarhoven t'Lens''+fromVL+ :: Lens' record field+ -> Lens record field+fromVL lens_ = Lens {..}+ where+ _get record = getConst (lens_ Const record)+ _set field = runIdentity . lens_ (\_ -> Identity field)+----------------------------------------------------------------------------+-- | t'Lens' form a 'Category', and can therefore be composed.+instance Category LensCore where+ id = Lens Prelude.id const+ Lens g1 s1 . Lens g2 s2 = Lens+ { _get = g1 >>> g2+ , _set = \f r -> s1 (s2 f (g1 r)) r+ }+----------------------------------------------------------------------------+-- | Set a field on a record+--+-- @+-- newtype Person = Person { _name :: String }+--+-- name :: Lens Person String+-- name = lens _name $ \\person n -> person { _name = n }+--+-- setName :: Person -> String -> Person+-- setName person newName = person & name .~ newName+-- @+infixr 4 .~+(.~) :: Lens record field -> field -> record -> record+(.~) _lens = _set _lens+----------------------------------------------------------------------------+-- | Synonym for '(.~)'+--+set :: Lens record field -> field -> record -> record+set = (.~)+----------------------------------------------------------------------------+-- | Set an options field on a record+--+-- @+-- newtype Person = Person { _name :: Maybe String }+--+-- name :: Lens Person (Maybe String)+-- name = lens _name $ \\person n -> person { _name = n }+--+-- setName :: Person -> String -> Person+-- setName person newName = person & name ?~ newName+-- @+infixr 4 ?~+(?~) :: Lens record (Maybe field) -> field -> record -> record+(?~) _lens f r = r & _lens .~ Just f+----------------------------------------------------------------------------+-- | Modify a field on a record by applying a function to it.+--+-- @+-- newtype Counter = Counter { _value :: Int }+--+-- value :: Lens Counter Int+-- value = lens _value $ \\counter v -> counter { _value = v }+--+-- increment :: Counter -> Counter+-- increment counter = counter & value %~ (+1)+-- @+infixr 4 %~+(%~) :: Lens record field -> (field -> field) -> record -> record+(%~) _lens f record = _set _lens (f (record ^. _lens)) record+----------------------------------------------------------------------------+-- | Synonym for '(%~)'+over :: Lens record field -> (field -> field) -> record -> record+over = (%~)+----------------------------------------------------------------------------+-- | Read a field from a record using a t'Lens'+--+-- @+-- newtype Person = Person { _name :: String }+-- deriving (Show, Eq)+--+-- name :: Lens Person String+-- name = lens _name $ \\person n -> person { _name = n }+--+-- getName :: Person -> String+-- getName = person ^. name+-- @+infixl 8 ^.+(^.) :: record -> Lens record field -> field+(^.) = flip _get+----------------------------------------------------------------------------+-- | Increment a @Num field => field@ on a record using a t'Lens'+--+-- @+-- newtype Person = Person { _age :: Int }+--+-- age :: Lens Person Int+-- age = lens _age $ \\person a -> person { _age = a }+--+-- birthday :: Person -> Person+-- birthday person = person & age +~ 1+-- @+infixr 4 +~+(+~) :: Num field => Lens record field -> field -> record -> record+(+~) _lens x record = record & _lens %~ (+x)+----------------------------------------------------------------------------+-- | Multiply a @Num@eric field on a record using a t'Lens'+--+-- @+-- newtype Circle = Circle { _radius :: Int }+--+-- radius :: Lens Circle Int+-- radius = lens _radius $ \\circle r -> circle { _radius = r }+--+-- expand :: Circle -> Circle+-- expand circle = circle & radius *~ 10+-- @+infixr 4 *~+(*~) :: Num field => Lens record field -> field -> record -> record+(*~) _lens x record = record & _lens %~ (*x)+----------------------------------------------------------------------------+-- | Divide a @Fractional@ field on a record using a t'Lens'+--+-- @+-- newtype Circle = Circle { _radius :: Int }+--+-- radius :: Lens Circle Int+-- radius = lens _radius $ \\circle r -> circle { _radius = r }+--+-- shrink :: Circle -> Circle+-- shrink circle = circle & radius //~ 10+-- @+infixr 4 //~+(//~) :: Fractional field => Lens record field -> field -> record -> record+(//~) _lens x record = record & _lens %~ (/x)+----------------------------------------------------------------------------+-- | Increment a @Num@eric field on a record using a t'Lens'+--+-- @+-- newtype Person = Person { _age :: Int }+--+-- age :: Lens Person Int+-- age = lens _age $ \\person a -> person { _age = a }+--+-- timeTravel :: Person -> Person+-- timeTravel person = person & age -~ 1+-- @+infixr 4 -~+(-~) :: Num field => Lens record field -> field -> record -> record+(-~) _lens x record = record & _lens %~ subtract x+----------------------------------------------------------------------------+-- | Monoidally append a field in a record using a t'Lens'+--+-- @+-- newtype List = List { _values :: [Int] }+--+-- values :: Lens List [Int]+-- values = lens _values $ \\l vs -> l { _values = vs }+--+-- addElement :: List -> List+-- addElement list = list & values <>~ [2]+--+-- addElement (List [])+-- -- List [2]+-- @+--+infixr 4 <>~+(<>~) :: Monoid field => Lens record field -> field -> record -> record+(<>~) _lens x record = record & _lens %~ (<> x)+----------------------------------------------------------------------------+-- | Execute a monadic action in @MonadState@ that returns a field. Sets the+-- return value equal to the field in the record.+--+-- As a reasonable mnemonic, this lets you store the result of a monadic action in a t'Lens' rather than+-- in a local variable.+--+-- @+-- do foo <- bar+-- ...+-- @+--+-- will store the result in a variable, while+--+-- @+-- do fooLens '<~' bar+-- ...+-- @+--+-- will store the result in field focused by the t'Lens'.+infixr 2 <~+(<~) :: MonadState record m => Lens record field -> m field -> m ()+l <~ mb = do+ b <- mb+ l .= b+----------------------------------------------------------------------------+-- | Modify a record in @MonadState@ monad at a field using a t'Lens'+--+-- @+-- newtype Model = Model { _value :: Int }+--+-- data Action = AddOne | SubtractOne+--+-- value :: Lens Model Int+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update :: Action -> Effect parent Model Action+-- update AddOne = do+-- value %= (+1)+-- @+infix 4 %=+(%=) :: MonadState record m => Lens record field -> (field -> field) -> m ()+(%=) _lens f = modify (\r -> r & _lens %~ f)+----------------------------------------------------------------------------+-- | Synonym for '(%=)'+modifying :: MonadState record m => Lens record field -> (field -> field) -> m ()+modifying = (%=)+----------------------------------------------------------------------------+-- | Modify the field of a record in @MonadState@ using a t'Lens', then+-- return the newly modified field from the updated record.+--+-- @+-- import Miso.String (ms)+--+-- newtype Model = Model { _value :: Int }+-- deriving (Show)+--+-- data Action = AddOne+--+-- value :: Lens Model Int+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update :: Action -> Effect parent Model Action+-- update AddOne = do+-- result <- value <%= (+1)+-- io_ $ consoleLog (ms result)+-- @+infix 4 <%=+(<%=) :: MonadState record m => Lens record field -> (field -> field) -> m field+l <%= f = do+ l %= f+ use l+----------------------------------------------------------------------------+-- | Assign the field of a record in @MonadState@ to a value using a t'Lens'+-- Return the value after assignment.+--+-- @+-- import Miso.String (ms)+--+-- newtype Model = Model { _value :: Int }+--+-- data Action = Assign Int+--+-- value :: Lens Model Int+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update :: Action -> Effect parent Model Action+-- update (Assign x) = do+-- result <- value <.= x+-- io_ $ consoleLog (ms result) -- x+-- @+infix 4 <.=+(<.=) :: MonadState record m => Lens record field -> field -> m field+l <.= b = do+ l .= b+ return b+----------------------------------------------------------------------------+-- | Assign the field of a record in a @MonadState@ to a value (wrapped in a 'Just')+-- using a t'Lens'. Return the value after assignment.+--+-- @+-- import Miso.String (ms)+--+-- newtype Model = Model { _value :: Maybe Int }+--+-- data Action = SetValue Int+--+-- value :: Lens Model (Maybe Int)+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update :: Action -> Effect parent Model Action+-- update (SetValue x) = do+-- result <- value <?= x+-- io_ $ consoleLog (ms result) -- Just 1+-- @+infix 4 <?=+(<?=) :: MonadState record m => Lens record (Maybe field) -> field -> m field+l <?= b = do+ l ?= b+ return b+----------------------------------------------------------------------------+-- | Assign the field of a record in a @MonadState@ to a value using a t'Lens'.+-- Returns the /previous/ value, before assignment.+--+-- @+-- import Miso.String (ms)+--+-- newtype Model = Model { _value :: Int }+-- deriving (Show, Eq)+--+-- data Action = Assign Int+-- deriving (Show, Eq)+--+-- value :: Lens Model Int+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update :: Action -> Effect parent Model Action+-- update (Assign x) = do+-- value .= x+-- previousValue <- value <<.= 1+-- io_ $ consoleLog $ ms previousValue -- prints value at x+-- @+infix 4 <<.=+(<<.=) :: MonadState record m => Lens record field -> field -> m field+l <<.= b = do+ old <- use l+ l .= b+ return old+----------------------------------------------------------------------------+-- | Retrieves the field associated with a record in @MonadReader@ using a t'Lens'.+--+-- @+-- import Miso.String (ms)+--+-- newtype Model = Model { _value :: Int }+-- deriving (Show, Eq)+--+-- data Action = PrintInt+--+-- value :: Lens Model Int+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update :: Action -> Effect parent Model Action+-- update PrintInt = do+-- Model x <- view value+-- io_ $ consoleLog (ms x) -- prints model value+-- @+----------------------------------------------------------------------------+view :: MonadReader record m => Lens record field -> m field+view lens_ = asks (^. lens_)+----------------------------------------------------------------------------+-- | Modifies the field of a record in @MonadState@ using a t'Lens'.+-- Returns the /previous/ value, before modification.+--+-- @+-- import Miso.String (ms)+--+-- newtype Model = Model { _value :: Int }+-- deriving (Show, Eq)+--+-- data Action = Modify (Int -> Int)+--+-- value :: Lens Model Int+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update :: Action -> Effect parent Model Action+-- update (Modify f) = do+-- value .= 2+-- result <- value <<%= f+-- io_ $ consoleLog (ms result) -- prints previous value of 2+-- @+infix 4 <<%=+(<<%=) :: MonadState record m => Lens record field -> (field -> field) -> m field+l <<%= f = do+ old <- use l+ l %= f+ return old+----------------------------------------------------------------------------+-- | Sets the value of a field in a record using @MonadState@ and a t'Lens'+--+-- @+-- newtype Model = Model { _value :: Int }+-- deriving (Show, Eq)+--+-- data Action = SetValue Int+--+-- value :: Lens Model Int+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update' :: Action -> Effect parent Model Action+-- update' (SetValue v) = value .= v+-- @+infix 4 .=+(.=) :: MonadState record m => Lens record field -> field -> m ()+(.=) _lens f = modify (\r -> r & _lens .~ f)+----------------------------------------------------------------------------+-- | Synonym for '(.=)'+assign :: MonadState record m => Lens record field -> field -> m ()+assign = (.=)+----------------------------------------------------------------------------+-- | Retrieves the value of a field in a record using a t'Lens' inside @MonadState@+--+-- @+-- import Miso.String (ms)+--+-- newtype Model = Model { _value :: Int }+-- deriving (Show, Eq)+--+-- data Action = SetValue Int+--+-- value :: Lens Model Int+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update :: Action -> Effect parent Model Action+-- update (SetValue x) = do+-- value .= x+-- result <- use value+-- io_ $ consoleLog (ms result) -- prints the value of x+-- @+use :: MonadState record m => Lens record field -> m field+use _lens = gets (^. _lens)+----------------------------------------------------------------------------+-- | Sets the value of a field in a record using a t'Lens' inside a @MonadState@+-- The value is wrapped in a @Just@ before being assigned.+--+-- @+-- newtype Model = Model { _value :: Maybe Int }+-- deriving (Show, Eq)+--+-- data Action = AssignValue Int+--+-- value :: Lens Model (Maybe Int)+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update :: Action -> Effect parent Model Action+-- update (AssignValue x) = value ?= x+-- @+infix 4 ?=+(?=) :: MonadState record m => Lens record (Maybe field) -> field -> m ()+(?=) _lens value = _lens .= Just value+----------------------------------------------------------------------------+-- | Alters the @Just@ value of a field in a record using a t'Lens' inside a @MonadState@+--+-- @+-- newtype Model = Model { _value :: Maybe Int }+-- deriving (Show, Eq)+--+-- data Action = IncrementIfJust+--+-- value :: Lens Model (Maybe Int)+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update :: Action -> Effect parent Model Action+-- update IncrementIfJust = value %?= (+1)+--+-- @+infix 4 %?=+(%?=) :: MonadState record m => Lens record (Maybe field) -> (field -> field) -> m ()+(%?=) _lens f = _lens %= \case+ Nothing -> Nothing+ Just x -> Just (f x)+----------------------------------------------------------------------------+-- | Increments the value of a @Num@eric field of a record using a t'Lens'+-- inside a @State@ Monad.+--+-- @+-- newtype Model = Model { _value :: Int }+-- deriving (Show, Eq)+--+-- data Action = IncrementBy Int+--+-- value :: Lens Model Int+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update :: Action -> Effect parent Model Action+-- update (IncrementBy x) = value += x+-- @+infix 4 +=+(+=) :: (MonadState record m, Num field) => Lens record field -> field -> m ()+(+=) _lens f = modify (\r -> r & _lens +~ f)+----------------------------------------------------------------------------+-- | Multiplies the value of a @Num@eric field of a record using a t'Lens'+-- inside a @State@ Monad.+--+-- @+-- newtype Model = Model { _value :: Int }+-- deriving (Show, Eq)+--+-- data Action = MultiplyBy Int+--+-- value :: Lens Model Int+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update :: Action -> Effect parent Model Action+-- update (MultiplyBy x) = value *= x+-- @+infix 4 *=+(*=) :: (MonadState record m, Num field) => Lens record field -> field -> m ()+(*=) _lens f = modify (\r -> r & _lens *~ f)+----------------------------------------------------------------------------+-- | Divides the value of a @Fractional@ field of a record using a t'Lens'+-- inside a @State@ Monad.+--+-- @+-- newtype Model = Model { _value :: Double }+-- deriving (Show, Eq)+--+-- data Action = DivideBy Double+--+-- value :: Lens Model Double+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update :: Action -> Effect parent Model Action+-- update (DivideBy x) = value //= x+-- @+infix 4 //=+(//=) :: (MonadState record m, Fractional field) => Lens record field -> field -> m ()+(//=) _lens f = modify (\r -> r & _lens %~ (/ f))+----------------------------------------------------------------------------+-- | Subtracts the value of a @Num@eric field of a record using a t'Lens'+-- inside of a @State@ Monad.+--+-- @+-- newtype Model = Model { _value :: Double }+-- deriving (Show, Eq)+--+-- data Action = SubtractBy Double+--+-- value :: Lens Model Double+-- value = lens _value $ \\p x -> p { _value = x }+--+-- update :: Action -> Effect parent Model Action+-- update (SubtractBy x) = value -= x+-- @+infix 4 -=+(-=) :: (MonadState record m, Num field) => Lens record field -> field -> m ()+(-=) _lens f = modify (\r -> r & _lens -~ f)+---------------------------------------------------------------------------------+-- | t'Lens' that operates on the first element of a tuple+--+-- @+-- update AddOne = do+-- _1 += 1+-- @+_1 :: Lens (a,b) a+_1 = lens fst $ \(_,b) x -> (x,b)+---------------------------------------------------------------------------------+-- | t'Lens' that operates on the second element of a tuple+--+-- @+-- update AddOne = do+-- _2 += 1+-- @+_2 :: Lens (a,b) b+_2 = lens snd $ \(a,_) x -> (a,x)+---------------------------------------------------------------------------------+-- | t'Lens' that operates on itself+--+-- @+-- update AddOne = do+-- _id += 1+-- @+_id :: Lens a a+_id = Control.Category.id+---------------------------------------------------------------------------------+-- | t'Lens' that operates on itself+--+-- @+-- update AddOne = do+-- this += 1+-- @+this :: Lens a a+this = _id+---------------------------------------------------------------------------------+-- | Smart constructor 'lens' function. Used to easily construct a t'Lens'+--+-- > name :: Lens Person String+-- > name = lens _name $ \p n -> p { _name = n }+--+lens+ :: (record -> field)+ -> (record -> field -> record)+ -> Lens record field+lens getter setter = Lens getter (flip setter)+----------------------------------------------------------------------------+data Prism s a+ = Prism+ { _up :: a -> s+ , _down :: s -> Maybe a+ }+----------------------------------------------------------------------------+review :: Prism s a -> a -> s+review = _up+----------------------------------------------------------------------------+preview :: MonadReader r m => Prism r a -> m (Maybe a)+preview = asks . preview+----------------------------------------------------------------------------+preuse :: MonadState s m => Prism s a -> m (Maybe a)+preuse = gets . preview+----------------------------------------------------------------------------+_Left :: Prism (Either a b) a+_Left = prism Left $ either Just (const Nothing)+----------------------------------------------------------------------------+_Right :: Prism (Either a b) b+_Right = prism Right (either (const Nothing) Just)+----------------------------------------------------------------------------+_Just :: Prism (Maybe a) a+_Just = prism Just Prelude.id+----------------------------------------------------------------------------+_Nothing :: Prism (Maybe a) a+_Nothing = prism (const Nothing) Prelude.id+----------------------------------------------------------------------------+infixl 8 ^?+(^?) :: s -> Prism s a -> Maybe a +(^?) = flip preview+----------------------------------------------------------------------------+prism :: (a -> s) -> (s -> Maybe a) -> Prism s a+prism = Prism+----------------------------------------------------------------------------+-- | Class for getting and setting values across various container types.+--+-- > M.singleton 'a' "foo" & at 'a' .~ Just "bar"+-- > -- fromList [('a',"bar")]+--+-- > update (SetValue value)+-- > at 10 ?= value+--+-- @since 1.9.0.0+class At at where+ type family Index at :: Type+ -- ^ Index of the container+ type family IxValue at :: Type+ -- ^ Indexed value of the container+ at :: Index at -> Lens at (Maybe (IxValue at))+----------------------------------------------------------------------------+instance Ord k => At (Map k v) where+ type Index (Map k v) = k+ type IxValue (Map k v) = v+ at key = lens (M.lookup key) $ \m value ->+ case value of+ Nothing -> M.delete key m+ Just v -> M.insert key v m+----------------------------------------------------------------------------+instance At (IntMap v) where+ type Index (IntMap v) = Int+ type IxValue (IntMap v) = v+ at key = lens (IM.lookup key) $ \m value ->+ case value of+ Nothing -> IM.delete key m+ Just v -> IM.insert key v m+----------------------------------------------------------------------------+instance Ord k => At (Set k) where+ type Index (Set k) = k+ type IxValue (Set k) = ()+ at key = Lens {..}+ where+ _set = \v m ->+ case v of+ Nothing -> S.delete key m+ Just () -> S.insert key m+ _get m+ | S.member key m = Just ()+ | otherwise = Nothing+----------------------------------------------------------------------------+instance At IntSet where+ type Index IntSet = Int+ type IxValue IntSet = ()+ at key = Lens {..}+ where+ _set = \v m ->+ case v of+ Nothing -> IS.delete key m+ Just () -> IS.insert key m+ _get m+ | IS.member key m = Just ()+ | otherwise = Nothing+----------------------------------------------------------------------------+instance At [a] where+ type Index [a] = Int+ type IxValue [a] = a+ at key = Lens {..}+ where+ _set Nothing m+ | key < 0 = m+ | otherwise = splitAt key m & \(lhs, rhs) -> lhs <> drop 1 rhs+ _set (Just v) m+ | key < 0 = m+ | otherwise = splitAt key m & \(lhs, rhs) ->+ case rhs of+ [] -> lhs+ _ : xs -> lhs <> (v : xs)+ _get = lookup key . zip [0..]+----------------------------------------------------------------------------
+ src/Miso/Lens/TH.hs view
@@ -0,0 +1,142 @@+-----------------------------------------------------------------------------+{-# LANGUAGE LambdaCase #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Lens.TH+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+-----------------------------------------------------------------------------+module Miso.Lens.TH+ ( -- ** TH+ makeLenses+ , makeClassy+ -- ** Re-exports+ , lens+ , compose+ , this+ , Lens+ ) where+-----------------------------------------------------------------------------+import Data.Char+import Data.Maybe+import Language.Haskell.TH+-----------------------------------------------------------------------------+import Miso.Util (compose)+import Miso.Lens (this, lens, Lens)+-----------------------------------------------------------------------------+-- | Automatically generates Haskell lenses via template-haskell.+--+makeLenses :: Name -> Q [Dec]+makeLenses name = do+ reify name >>= \case+ TyConI (NewtypeD _ _ _ _ con _) -> do+ case con of+ RecC _ fieldNames ->+ pure (processFieldNames fieldNames)+ _ -> pure []+ TyConI (DataD _ _ _ _ cons _) ->+ flip concatMapM cons $ \case+ RecC _ fieldNames -> do+ pure (processFieldNames fieldNames)+ _ -> pure []+ _ -> pure []+ where+ processFieldNames fieldNames = concat+ [ mkFields fName (ConT name) fieldType+ | (fieldName, _, fieldType) <- fieldNames+ , let fName = nameBase fieldName+ , listToMaybe fName == Just '_'+ ]+ mkFields fieldName conType fieldType =+ let -- dmj: drops '_' prefix+ lensName = mkName (drop 1 fieldName)+ in+ [ FunD lensName+ [ Clause [] (NormalB (mkLens fieldName)) []+ ]+ , SigD lensName (mkLensType conType fieldType)+ ]+ concatMapM f xs =+ concat <$> mapM f xs+ mkLensType conType =+ AppT (AppT (ConT (mkName "Lens")) conType)+ mkLens n =+ AppE (AppE (VarE (mkName "lens")) (VarE (mkName n)))+ $ LamE [ VarP recName, VarP fieldName ]+ $ RecUpdE (VarE recName) [ (mkName n, VarE fieldName) ]+ where+ recName = mkName "record"+ fieldName = mkName "field"+-----------------------------------------------------------------------------+-- | Automatically generates classy lenses via template-haskell.+makeClassy :: Name -> Q [Dec]+makeClassy name = do+ reify name >>= \case+ TyConI (NewtypeD _ _ _ _ con _) -> do+ case con of+ RecC _ fieldNames ->+ pure (processFieldNames fieldNames)+ _ -> pure []+ TyConI (DataD _ _ _ _ cons _) ->+ flip concatMapM cons $ \case+ RecC _ fieldNames -> do+ pure (processFieldNames fieldNames)+ _ -> pure []+ _ -> pure []+ where+ instanceName =+ AppT (ConT (mkName ("Has" <> baseName))) (ConT name)+ baseName = nameBase name+ baseNameLower+ | x : xs <- baseName = toLower x : xs+ | otherwise = []+ processFieldNames fieldNames =+ [ InstanceD Nothing [] instanceName+ [ ValD (VarP (mkName baseNameLower)) (NormalB (VarE (mkName "this"))) []+ -- instance HasFoo Foo where foo = this+ ]+ , ClassD [] (mkName $ "Has" <> nameBase name)+ [ PlainTV (mkName baseNameLower) BndrReq+ ] [] $ reverse $ concat+ [ mkFields fName (VarT (mkName baseNameLower)) fieldType+ | (fieldName, _, fieldType) <- fieldNames+ , let fName = nameBase fieldName+ , listToMaybe fName == Just '_'+ ] +++ [ SigD+ (mkName baseNameLower) + (AppT+ (AppT+ (ConT (mkName "Lens"))+ (VarT (mkName baseNameLower)))+ (ConT name))+ ]+ ]+ mkFields fieldName varType fieldType =+ let -- dmj: drops '_' prefix+ lensName = mkName (drop 1 fieldName)+ in+ [ FunD lensName+ [ Clause [] (NormalB (wrapMkLens fieldName)) []+ ]+ -- fooX = lens _fooX (\r x -> r { _fooX = x }) . foo+ , SigD lensName (mkLensType varType fieldType)+ -- fooY :: Lens foo Int+ ]+ concatMapM f xs =+ concat <$> mapM f xs+ mkLensType varType x =+ AppT (AppT (ConT (mkName "Lens")) varType) x+ wrapMkLens n =+ AppE (AppE (VarE (mkName "compose")) (mkLens n)) (VarE (mkName baseNameLower))+ mkLens n+ = AppE (AppE (VarE (mkName "lens")) (VarE (mkName n)))+ $ LamE [ VarP recName, VarP fieldName ]+ $ RecUpdE (VarE recName) [ (mkName n, VarE fieldName) ]+ where+ recName = mkName "record"+ fieldName = mkName "field"+-------------------------------------------------------------------------------
src/Miso/Mathml.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Miso.Mathml--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental@@ -10,15 +10,23 @@ -- Example usage: -- -- @+-- xSquared :: View model action+-- xSquared =+-- math_ []+-- [ msup_ []+-- [ mi_ [] [text "x"]+-- , mn_ [] [text "2"]+-- ]+-- ] -- @ ----- More information on how to use `miso` is available on GitHub------ <http://github.com/dmjio/miso>+-- More complex example in [mathml](https://github.com/haskell-miso/miso-mathml). -- ---------------------------------------------------------------------------- module Miso.Mathml- ( module Miso.Mathml.Element+ ( -- * Elements+ module Miso.Mathml.Element ) where-+----------------------------------------------------------------------------- import Miso.Mathml.Element+-----------------------------------------------------------------------------
src/Miso/Mathml/Element.hs view
@@ -1,23 +1,234 @@+----------------------------------------------------------------------------- {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE NoImplicitPrelude #-} ----------------------------------------------------------------------------- -- | -- Module : Miso.Mathml.Element--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable ---------------------------------------------------------------------------- module Miso.Mathml.Element- ( -- * Construct an Element- nodeMathml+ ( -- ** Combinator+ nodeMathml+ -- ** Elements+ , math_+ , annotationXml_+ , annotation_+ , merror_+ , mfrac_+ , mi_+ , mmultiscripts_+ , mn_+ , mo_+ , mover_+ , mpadded_+ , mphantom_+ , mprescripts_+ , mroot_+ , mrow_+ , ms_+ , mspace_+ , msqrt_+ , mstyle_+ , msub_+ , msubsup_+ , msup_+ , mtable_+ , mtd_+ , mtext_+ , mtr_+ , munder_+ , munderover_+ , semantics_+ , mfenced_ ) where--import Miso.Html.Types-import Miso.String (MisoString)-import qualified Prelude as P---- | Used to construct `VNode`'s in `View`-nodeMathml :: MisoString -> [Attribute action] -> [View action] -> View action-nodeMathml = P.flip (node MATHML) P.Nothing+-----------------------------------------------------------------------------+import Miso.Types+-----------------------------------------------------------------------------+-- | Low-level helper used to construct 'MATHML' 'node' in 'Miso.Types.View'.+-- Most View helpers in this module are defined in terms of it.+nodeMathml :: MisoString -> [Attribute action] -> [View model action] -> View model action+nodeMathml nodeName = node MATHML nodeName+-----------------------------------------------------------------------------+-- | [\<annotation-xml\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/annotation-xml)+--+-- @since 1.9.0.0+annotationXml_ :: [Attribute action] -> [View model action] -> View model action+annotationXml_ = nodeMathml "annotation-xml"+-----------------------------------------------------------------------------+-- | [\<annotation\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/annotation)+--+-- @since 1.9.0.0+annotation_ :: [Attribute action] -> [View model action] -> View model action+annotation_ = nodeMathml "annotation"+-----------------------------------------------------------------------------+-- | [\<math\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/math)+--+-- @since 1.9.0.0+math_ :: [Attribute action] -> [View model action] -> View model action+math_ = nodeMathml "math"+-----------------------------------------------------------------------------+-- | [\<merror\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/merror)+--+-- @since 1.9.0.0+merror_ :: [Attribute action] -> [View model action] -> View model action+merror_ = nodeMathml "merror"+-----------------------------------------------------------------------------+-- | [\<mfrac\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mfrac)+--+-- @since 1.9.0.0+mfrac_ :: [Attribute action] -> [View model action] -> View model action+mfrac_ = nodeMathml "mfrac"+-----------------------------------------------------------------------------+-- | [\<mi\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mi)+--+-- @since 1.9.0.0+mi_ :: [Attribute action] -> [View model action] -> View model action+mi_ = nodeMathml "mi"+-----------------------------------------------------------------------------+-- | [\<mmultiscripts\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mmultiscripts)+--+-- @since 1.9.0.0+mmultiscripts_ :: [Attribute action] -> [View model action] -> View model action+mmultiscripts_ = nodeMathml "mmultiscripts"+-----------------------------------------------------------------------------+-- | [\<mn\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mn)+--+-- @since 1.9.0.0+mn_ :: [Attribute action] -> [View model action] -> View model action+mn_ = nodeMathml "mn"+-----------------------------------------------------------------------------+-- | [\<mo\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mo)+--+-- @since 1.9.0.0+mo_ :: [Attribute action] -> [View model action] -> View model action+mo_ = nodeMathml "mo"+-----------------------------------------------------------------------------+-- | [\<mover\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mover)+--+-- @since 1.9.0.0+mover_ :: [Attribute action] -> [View model action] -> View model action+mover_ = nodeMathml "mover"+-----------------------------------------------------------------------------+-- | [\<mpadded\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mpadded)+--+-- @since 1.9.0.0+mpadded_ :: [Attribute action] -> [View model action] -> View model action+mpadded_ = nodeMathml "mpadded"+-----------------------------------------------------------------------------+-- | [\<mphantom\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mphantom)+--+-- @since 1.9.0.0+mphantom_ :: [Attribute action] -> [View model action] -> View model action+mphantom_ = nodeMathml "mphantom"+-----------------------------------------------------------------------------+-- | [\<mprescripts\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mprescripts)+--+-- @since 1.9.0.0+mprescripts_ :: [Attribute action] -> [View model action] -> View model action+mprescripts_ = nodeMathml "mprescripts"+-----------------------------------------------------------------------------+-- | [\<mroot\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mroot)+--+-- @since 1.9.0.0+mroot_ :: [Attribute action] -> [View model action] -> View model action+mroot_ = nodeMathml "mroot"+-----------------------------------------------------------------------------+-- | [\<mrow\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mrow)+--+-- @since 1.9.0.0+mrow_ :: [Attribute action] -> [View model action] -> View model action+mrow_ = nodeMathml "mrow"+-----------------------------------------------------------------------------+-- | [\<ms\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/ms)+--+-- @since 1.9.0.0+ms_ :: [Attribute action] -> [View model action] -> View model action+ms_ = nodeMathml "ms"+-----------------------------------------------------------------------------+-- | [\<mspace\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mspace)+--+-- @since 1.9.0.0+mspace_ :: [Attribute action] -> [View model action] -> View model action+mspace_ = nodeMathml "mspace"+-----------------------------------------------------------------------------+-- | [\<msqrt\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/msqrt)+--+-- @since 1.9.0.0+msqrt_ :: [Attribute action] -> [View model action] -> View model action+msqrt_ = nodeMathml "msqrt"+-----------------------------------------------------------------------------+-- | [\<mstyle\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mstyle)+--+-- @since 1.9.0.0+mstyle_ :: [Attribute action] -> [View model action] -> View model action+mstyle_ = nodeMathml "mstyle"+-----------------------------------------------------------------------------+-- | [\<msub\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/msub)+--+-- @since 1.9.0.0+msub_ :: [Attribute action] -> [View model action] -> View model action+msub_ = nodeMathml "msub"+-----------------------------------------------------------------------------+-- | [\<msubsup\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/msubsup)+--+-- @since 1.9.0.0+msubsup_ :: [Attribute action] -> [View model action] -> View model action+msubsup_ = nodeMathml "msubsup"+-----------------------------------------------------------------------------+-- | [\<msup\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/msup)+--+-- @since 1.9.0.0+msup_ :: [Attribute action] -> [View model action] -> View model action+msup_ = nodeMathml "msup"+-----------------------------------------------------------------------------+-- | [\<mtable\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mtable)+--+-- @since 1.9.0.0+mtable_ :: [Attribute action] -> [View model action] -> View model action+mtable_ = nodeMathml "mtable"+-----------------------------------------------------------------------------+-- | [\<mtd\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mtd)+--+-- @since 1.9.0.0+mtd_ :: [Attribute action] -> [View model action] -> View model action+mtd_ = nodeMathml "mtd"+-----------------------------------------------------------------------------+-- | [\<mtext\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mtext)+--+-- @since 1.9.0.0+mtext_ :: [Attribute action] -> [View model action] -> View model action+mtext_ = nodeMathml "mtext"+-----------------------------------------------------------------------------+-- | [\<mtr\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mtr)+--+-- @since 1.9.0.0+mtr_ :: [Attribute action] -> [View model action] -> View model action+mtr_ = nodeMathml "mtr"+-----------------------------------------------------------------------------+-- | [\<munder\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/munder)+--+-- @since 1.9.0.0+munder_ :: [Attribute action] -> [View model action] -> View model action+munder_ = nodeMathml "munder"+-----------------------------------------------------------------------------+-- | [\<munderover\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/munderover)+--+-- @since 1.9.0.0+munderover_ :: [Attribute action] -> [View model action] -> View model action+munderover_ = nodeMathml "munderover"+-----------------------------------------------------------------------------+-- | [\<semantics\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/semantics)+--+-- @since 1.9.0.0+semantics_ :: [Attribute action] -> [View model action] -> View model action+semantics_ = nodeMathml "semantics"+-----------------------------------------------------------------------------+-- | [\<semantics\>](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element/mfenced)+--+-- @since 1.9.0.0+mfenced_ :: [Attribute action] -> [View model action] -> View model action+mfenced_ = nodeMathml "mfenced"+-----------------------------------------------------------------------------
+ src/Miso/Mathml/Property.hs view
@@ -0,0 +1,232 @@+-----------------------------------------------------------------------------+{-# LANGUAGE OverloadedStrings #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Mathml.Property+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- MathML attributes.+--+-- We recommend referring to [MDN Attributes reference](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Attribute)+-- for details on how each attribute can be used.+--+----------------------------------------------------------------------------+module Miso.Mathml.Property+ ( -- * Global attributes+ dir_+ , displaystyle_+ , scriptlevel_+ -- * Regular attributes+ , accent_+ , accentunder_+ , align_+ , columnalign_+ , columnlines_+ , columnspacing_+ , columnspan_+ , depth_+ , display_+ , fence_+ , frame_+ , framespacing_+ , height_+ , href_+ , id_+ , linethickness_+ , lspace_+ , mathbackground_+ , mathcolor_+ , mathsize_+ , mathvariant_+ , maxsize_+ , minsize_+ , movablelimits_+ , notation_+ , rowalign_+ , rowlines_+ , rowspacing_+ , rowspan_+ , rspace_+ , separator_+ , stretchy_+ , symmetric_+ , voffset_+ , width_+ , close_+ , open_+ ) where+-----------------------------------------------------------------------------+import Miso.Types+import Miso.Property+-----------------------------------------------------------------------------+-- | [dir](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Global_attributes/dir)+--+-- @since 1.9.0.0+dir_ :: MisoString -> Attribute action+dir_ = textProp "dir"+-----------------------------------------------------------------------------+-- | [displaystyle](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Global_attributes/displaystyle)+--+-- @since 1.9.0.0+displaystyle_ :: MisoString -> Attribute action+displaystyle_ = textProp "displaystyle"+------------------------------------------------------------------------------+-- | [scriptlevel](https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Global_attributes/scriptlevel)+--+-- @since 1.9.0.0+scriptlevel_ :: Int -> Attribute action+scriptlevel_ = intProp "scriptlevel"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+accent_ :: Bool -> Attribute action+accent_ = boolProp "accent"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+accentunder_ :: Bool -> Attribute action+accentunder_ = boolProp "accentunder"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+align_ :: Bool -> Attribute action+align_ = boolProp "align"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+columnalign_ :: MisoString -> Attribute action+columnalign_ = textProp "columnalign"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+columnlines_ :: MisoString -> Attribute action+columnlines_ = textProp "columnlines"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+columnspacing_ :: MisoString -> Attribute action+columnspacing_ = textProp "columnspacing"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+columnspan_ :: Int -> Attribute action+columnspan_ = intProp "columnspan"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+depth_ :: MisoString -> Attribute action+depth_ = textProp "depth"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+display_ :: MisoString -> Attribute action+display_ = textProp "display"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+fence_ :: Bool -> Attribute action+fence_ = boolProp "fence"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+frame_ :: MisoString -> Attribute action+frame_ = textProp "frame"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+framespacing_ :: MisoString -> Attribute action+framespacing_ = textProp "framespacing"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+height_ :: MisoString -> Attribute action+height_ = textProp "height"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+href_ :: MisoString -> Attribute action+href_ = textProp "href"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+id_ :: MisoString -> Attribute action+id_ = textProp "id"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+linethickness_ :: MisoString -> Attribute action+linethickness_ = textProp "linethickness"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+lspace_ :: MisoString -> Attribute action+lspace_ = textProp "lspace"+-- | @since 1.9.0.0+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+mathbackground_ :: MisoString -> Attribute action+mathbackground_ = textProp "mathbackground"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+mathcolor_ :: MisoString -> Attribute action+mathcolor_ = textProp "mathcolor"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+mathsize_ :: MisoString -> Attribute action+mathsize_ = textProp "mathsize"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+mathvariant_ :: MisoString -> Attribute action+mathvariant_ = textProp "mathvariant"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+maxsize_ :: MisoString -> Attribute action+maxsize_ = textProp "maxsize"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+minsize_ :: MisoString -> Attribute action+minsize_ = textProp "minsize"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+movablelimits_ :: Bool -> Attribute action+movablelimits_ = boolProp "movablelimits"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+notation_ :: MisoString -> Attribute action+notation_ = textProp "notation"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+rowalign_ :: MisoString -> Attribute action+rowalign_ = textProp "rowalign"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+rowlines_ :: MisoString -> Attribute action+rowlines_ = textProp "rowlines"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+rowspacing_ :: MisoString -> Attribute action+rowspacing_ = textProp "rowspacing"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+rowspan_ :: Int -> Attribute action+rowspan_ = intProp "rowspan"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+rspace_ :: MisoString -> Attribute action+rspace_ = textProp "rspace"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+separator_ :: Bool -> Attribute action+separator_ = boolProp "separator"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+stretchy_ :: Bool -> Attribute action+stretchy_ = boolProp "stretchy"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+symmetric_ :: Bool -> Attribute action+symmetric_ = boolProp "symmetric"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+voffset_ :: MisoString -> Attribute action+voffset_ = textProp "voffset"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+width_ :: MisoString -> Attribute action+width_ = textProp "width"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+close_ :: MisoString -> Attribute action+close_ = textProp "close"+-----------------------------------------------------------------------------+-- | @since 1.9.0.0+open_ :: MisoString -> Attribute action+open_ = textProp "open"+-----------------------------------------------------------------------------
+ src/Miso/Media.hs view
@@ -0,0 +1,261 @@+-----------------------------------------------------------------------------+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Media+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+----------------------------------------------------------------------------+module Miso.Media+ ( -- *** Types+ Media (..)+ , NetworkState (..)+ , ReadyState (..)+ , Stream+ -- *** Methods+ , canPlayType+ , load+ , play+ , pause+ , srcObject+ -- *** Properties+ , autoplay+ , controls+ , currentSrc+ , currentTime+ , defaultMuted+ , defaultPlaybackRate+ , duration+ , ended+ , loop+ , mediaGroup+ , muted+ , networkState+ , paused+ , playbackRate+ , poster+ , preload+ , readyState+ , seeking+ , videoHeight+ , videoWidth+ , volume+ -- *** Event Map+ , mediaEvents+ ) where+-----------------------------------------------------------------------------+import Control.Monad+-----------------------------------------------------------------------------+import Miso.DSL+import Miso.Event+import Miso.String+-----------------------------------------------------------------------------+-- | Type that abstracts over [Audio](https://www.w3schools.com/jsref/dom_obj_audio.asp)+-- or [Video](https://www.w3schools.com/jsref/dom_obj_video.asp) media objects.+--+-- You can create them in the View using 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_'.+-- To get the corresponding t'Media' object from the DOM, you can use+--+-- @+-- media <- t'Media' \<$\> 'Miso.FFI.getElementById' "myVideo"+-- @+newtype Media = Media JSVal+ deriving (ToJSVal, Eq)+-----------------------------------------------------------------------------+-- | Possible values of [networkState](https://www.w3schools.com/tags/av_prop_networkstate.asp) property.+data NetworkState+ = NETWORK_EMPTY+ | NETWORK_IDLE+ | NETWORK_LOADING+ | NETWORK_NO_SOURCE+ deriving (Show, Eq, Enum)+-----------------------------------------------------------------------------+-- | Possible values of [readyState](https://www.w3schools.com/tags/av_prop_readystate.asp) property.+data ReadyState+ = HAVE_NOTHING+ | HAVE_METADATA+ | HAVE_CURRENT_DATA+ | HAVE_FUTURE_DATA+ | HAVE_ENOUGH_DATA+ deriving (Show, Eq, Enum)+-----------------------------------------------------------------------------+-- | The [load](https://www.w3schools.com/tags/av_met_load.asp) method+-- re-loads the audio/video element.+load :: Media -> IO ()+load (Media m) = void $ m # ("load" :: MisoString) $ ()+-----------------------------------------------------------------------------+-- | The [play](https://www.w3schools.com/tags/av_met_play.asp) method starts+-- playing the current audio or video.+play :: Media -> IO ()+play (Media m) = void $ m # ("play" :: MisoString) $ ()+-----------------------------------------------------------------------------+-- | The [pause](https://www.w3schools.com/tags/av_met_pause.asp) method pauses+-- the currently playing audio or video.+pause :: Media -> IO ()+pause (Media a) = void $ a # ("pause" :: MisoString) $ ()+-----------------------------------------------------------------------------+-- | The [canPlayType](https://www.w3schools.com/tags/av_met_canplaytype.asp)+-- method checks if the browser can play the specified audio/video type.+canPlayType :: Media -> IO MisoString+canPlayType (Media m) = do+ fromJSValUnchecked =<< do+ m # ("canPlayType" :: MisoString) $ ()+-----------------------------------------------------------------------------+-- | The [autoplay](https://www.w3schools.com/tags/av_prop_autoplay.asp) property+-- returns whether the audio/video should start playing as soon as it is loaded.+--+-- To set the property, use 'Miso.Html.Property.autoplay_'+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.+autoplay :: Media -> IO Bool+autoplay (Media m) = fromJSValUnchecked =<< m ! ("autoplay" :: MisoString)+-----------------------------------------------------------------------------+-- | The [controls](https://www.w3schools.com/tags/av_prop_controls.asp)+-- property returns whether the browser should display standard audio/video controls.+--+-- To set the property, use 'Miso.Html.Property.controls_'+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.+controls :: Media -> IO Bool+controls (Media m) = fromJSValUnchecked =<< m ! ("controls" :: MisoString)+-----------------------------------------------------------------------------+-- | The [currentSrc](https://www.w3schools.com/tags/av_prop_currentsrc.asp)+-- property returns the URL of the current audio/video.+currentSrc :: Media -> IO MisoString+currentSrc (Media m) = fromJSValUnchecked =<< m ! ("currentSrc" :: MisoString)+-----------------------------------------------------------------------------+-- | The [currentTime](https://www.w3schools.com/tags/av_prop_currenttime.asp)+-- property returns the current position (in seconds) of the audio/video playback.+--+-- To set the current time, use 'Miso.Html.Property.currentTime_'+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.+currentTime :: Media -> IO Double+currentTime (Media m) = fromJSValUnchecked =<< m ! ("currentTime" :: MisoString)+-----------------------------------------------------------------------------+-- | The [defaultMuted](https://www.w3schools.com/tags/av_prop_defaultmuted.asp)+-- property returns whether the audio/video should be muted by default.+--+-- To set the property, use 'Miso.Html.Property.defaultMuted_'+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.+defaultMuted :: Media -> IO Bool+defaultMuted (Media m) = fromJSValUnchecked =<< m ! ("defaultMuted" :: MisoString)+-----------------------------------------------------------------------------+-- | The [defaultPlaybackRate](https://www.w3schools.com/tags/av_prop_defaultplaybackrate.asp)+-- property returns the default playback speed of the audio/video.+--+-- To set the property, use 'Miso.Html.Property.defaultPlaybackRate_'+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.+defaultPlaybackRate :: Media -> IO Double+defaultPlaybackRate (Media m) = fromJSValUnchecked =<< m ! ("defaultPlaybackRate" :: MisoString)+-----------------------------------------------------------------------------+-- | The [duration](https://www.w3schools.com/tags/av_prop_duration.asp) property+-- returns the length of the current audio/video, in seconds.+duration :: Media -> IO Double+duration (Media m) = fromJSValUnchecked =<< m ! ("duration" :: MisoString)+-----------------------------------------------------------------------------+-- | The [ended](https://www.w3schools.com/tags/av_prop_ended.asp) property+-- returns whether the playback of the audio/video has ended.+ended :: Media -> IO Bool+ended (Media m) = fromJSValUnchecked =<< m ! ("ended" :: MisoString)+-----------------------------------------------------------------------------+-- | The [loop](https://www.w3schools.com/tags/av_prop_loop.asp) property+-- returns whether the audio/video should start playing over again when it is finished.+--+-- To set the property, use 'Miso.Html.Property.loop_'+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.+loop :: Media -> IO Bool+loop (Media m) = fromJSValUnchecked =<< m ! ("loop" :: MisoString)+-----------------------------------------------------------------------------+-- | The [mediaGroup](https://www.w3schools.com/tags/av_prop_mediagroup.asp) property+-- returns the name of the media group the audio/video is a part of.+--+-- To set the property, use 'Miso.Html.Property.mediaGroup_'+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.+mediaGroup :: Media -> IO MisoString+mediaGroup (Media m) = fromJSValUnchecked =<< m ! ("mediaGroup" :: MisoString)+-----------------------------------------------------------------------------+-- | The [muted](https://www.w3schools.com/tags/av_prop_muted.asp) property+-- returns whether the audio/video should be muted (sound turned off).+--+-- To set the property, use 'Miso.Html.Property.muted_'+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.+muted :: Media -> IO Bool+muted (Media m) = fromJSValUnchecked =<< m ! ("muted" :: MisoString)+-----------------------------------------------------------------------------+-- | The [networkState](https://www.w3schools.com/tags/av_prop_networkstate.asp)+-- property returns the current network state (activity) of the audio/video.+networkState :: Media -> IO NetworkState+networkState (Media m) = do+ number <- fromJSValUnchecked =<< m ! ("networkState" :: MisoString)+ pure (toEnum number)+-----------------------------------------------------------------------------+-- | The [paused](https://www.w3schools.com/tags/av_prop_paused.asp) property+-- returns whether the audio/video is paused.+paused :: Media -> IO Bool+paused (Media a) = fromJSValUnchecked =<< a ! ("paused" :: MisoString)+-----------------------------------------------------------------------------+-- | The [playbackRate](https://www.w3schools.com/tags/av_prop_playbackRate.asp)+-- property returns the current playback speed of the audio/video.+--+-- To set the playback rate, use 'Miso.Html.Property.playbackRate_'+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.+playbackRate :: Media -> IO Double+playbackRate (Media a) = fromJSValUnchecked =<< a ! ("playbackRate" :: MisoString)+-----------------------------------------------------------------------------+-- | The [poster](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/poster) property+-- of the HTMLVideoElement interface is a string that reflects the URL for an image+-- to be shown while no video data is available.+--+-- Specific to videos.+poster :: Media -> IO MisoString+poster (Media a) = fromJSValUnchecked =<< a ! ("poster" :: MisoString)+-----------------------------------------------------------------------------+-- | The [preload](https://www.w3schools.com/tags/av_prop_preload.asp) property+-- returns whether the audio/video should start loading as soon as the page loads.+--+-- To set the preload property, use 'Miso.Html.Property.preload_'+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.+preload :: Media -> IO MisoString+preload (Media a) = fromJSValUnchecked =<< a ! ("preload" :: MisoString)+-----------------------------------------------------------------------------+-- | The [readyState](https://www.w3schools.com/tags/av_prop_readyState.asp) property+-- returns the current ready state of the audio/video.+readyState :: Media -> IO ReadyState+readyState (Media a) = do+ number <- fromJSValUnchecked =<< a ! ("readyState" :: MisoString)+ pure (toEnum number)+-----------------------------------------------------------------------------+-- | The [seeking](https://www.w3schools.com/tags/av_prop_seeking.asp) property+-- returns whether the user is currently seeking in the audio/video.+seeking :: Media -> IO Bool+seeking (Media a) = fromJSValUnchecked =<< a ! ("seeking" :: MisoString)+-----------------------------------------------------------------------------+-- | The HTMLVideoElement interface's read-only+-- [videoHeight](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/videoHeight)+-- property indicates the intrinsic height of the video, expressed in CSS pixels.+videoHeight :: Media -> IO Int+videoHeight (Media m) = fromJSValUnchecked =<< m ! ("videoHeight" :: MisoString)+-----------------------------------------------------------------------------+-- | The HTMLVideoElement interface's read-only+-- [videoWidth](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/videoWidth)+-- property indicates the intrinsic width of the video, expressed in CSS pixels+videoWidth :: Media -> IO Int+videoWidth (Media m) = fromJSValUnchecked =<< m ! ("videoWidth" :: MisoString)+-----------------------------------------------------------------------------+-- | The [volume](https://www.w3schools.com/tags/av_prop_volume.asp) property+-- returns the current volume of the audio/video.+--+-- To set the volume, use 'Miso.Html.Property.volume_'+-- on the 'Miso.Html.Element.audio_' or 'Miso.Html.Element.video_' element.+volume :: Media -> IO Double+volume (Media m) = fromJSValUnchecked =<< m ! ("volume" :: MisoString)+-----------------------------------------------------------------------------+-- | A media Stream+type Stream = JSVal+-----------------------------------------------------------------------------+-- | Sets the `srcObject` on audio or video elements.+srcObject :: Stream -> Media -> IO ()+srcObject stream (Media media) = setField media "srcObject" stream+-----------------------------------------------------------------------------
@@ -0,0 +1,154 @@+-----------------------------------------------------------------------------+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE CPP #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Navigator+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+----------------------------------------------------------------------------+module Miso.Navigator+ ( -- ** User media+ getUserMedia+ , userMedia+ , UserMedia (..)+ , Stream+ -- ** Clipboard+ , copyClipboard+ -- ** OnLine+ , isOnLine+ -- ** Geolocation+ , geolocation+ , Geolocation (..)+ , GeolocationError (..)+ , GeolocationErrorCode (..)+ ) where+-----------------------------------------------------------------------------+import Control.Monad ((<=<))+import Prelude hiding ((!!))+-----------------------------------------------------------------------------+import Miso.DSL+import Miso.String+import Miso.Effect+import qualified Miso.FFI.Internal as FFI+----------------------------------------------------------------------------+-- | A media stream+type Stream = JSVal+----------------------------------------------------------------------------+-- | Get access to user's media devices.+--+-- <https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia>+--+getUserMedia+ :: UserMedia+ -- ^ Options+ -> (Stream -> action)+ -- ^ Successful callback+ -> (JSVal -> action)+ -- ^ Errorful callback+ -> Effect parent model action+getUserMedia UserMedia {..} successful errorful =+ withSink $ \sink ->+ FFI.getUserMedia audio video+ (sink . successful)+ (sink . errorful)+-----------------------------------------------------------------------------+-- | Get access to the user's clipboard.+--+-- <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/clipboard>+--+copyClipboard+ :: MisoString+ -- ^ Options+ -> action+ -- ^ Successful callback+ -> (JSVal -> action)+ -- ^ Errorful callback+ -> Effect parent model action+copyClipboard txt successful errorful =+ withSink $ \sink ->+ FFI.copyClipboard txt+ (sink successful)+ (sink . errorful)+-----------------------------------------------------------------------------+-- | Get user's online status+--+-- <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine>+--+isOnLine+ :: (Bool -> action)+ -- ^ Successful callback+ -> Effect parent model action+isOnLine action = io (action <$> FFI.isOnLine)+-----------------------------------------------------------------------------+-- | Type for dealing with 'navigator.mediaDevices.getUserMedia'+--+-- <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/mediaDevices>+--+data UserMedia+ = UserMedia+ { audio, video :: Bool+ } deriving (Show, Eq)+-----------------------------------------------------------------------------+-- | Default t'UserMedia'+userMedia :: UserMedia+userMedia = UserMedia True True+-----------------------------------------------------------------------------+-- | Geolocation fetching+--+-- <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/geolocation>+--+geolocation+ :: (Geolocation -> action)+ -> (GeolocationError -> action)+ -> Effect parent model action+geolocation successful errorful = do+ withSink $ \sink ->+ FFI.geolocation+ (sink . successful <=< fromJSValUnchecked)+ (sink . errorful <=< fromJSValUnchecked)+-----------------------------------------------------------------------------+-- | Geolocation errors+data GeolocationError = GeolocationError GeolocationErrorCode MisoString+ deriving (Show, Eq)+-----------------------------------------------------------------------------+instance FromJSVal GeolocationError where+ fromJSVal v = do+ code <- fromJSVal =<< (v ! "code")+ msg <- fromJSVal =<< (v ! "message")+ pure (GeolocationError <$> code <*> msg)+-----------------------------------------------------------------------------+-- | Geolocation error code+data GeolocationErrorCode+ = PERMISSION_DENIED+ | POSITION_UNAVAILABLE+ | TIMEOUT+ deriving (Enum, Show, Eq)+-----------------------------------------------------------------------------+instance FromJSVal GeolocationErrorCode where+ fromJSVal code =+ fromJSValUnchecked code >>= \case+ (1 :: Int) -> pure (Just PERMISSION_DENIED)+ 2 -> pure (Just POSITION_UNAVAILABLE)+ 3 -> pure (Just TIMEOUT)+ _ -> pure Nothing+-----------------------------------------------------------------------------+-- | Geolocation holds latitude, longitude and accuracy, among others.+data Geolocation+ = Geolocation+ { latitude, longitude, accuracy :: Double+ } deriving (Show, Eq)+-----------------------------------------------------------------------------+instance FromJSVal Geolocation where+ fromJSVal geo = do+ lat <- fromJSVal =<< geo ! "coords" ! "latitude"+ lon <- fromJSVal =<< geo ! "coords" ! "longitude"+ acc <- fromJSVal =<< geo ! "coords" ! "accuracy"+ pure (Geolocation <$> lat <*> lon <*> acc)+-----------------------------------------------------------------------------
+ src/Miso/Prelude.hs view
@@ -0,0 +1,47 @@+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Prelude+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- A custom Prelude for [miso](https://github.com/dmjio/miso).+--+-- Can consume via @NoImplicitPrelude@ or using Cabal mixins.+--+-- @+-- import Miso.Prelude+-- @+--+-- Almost identical to the existing @Prelude@, except we re-export the+-- @Miso@ module, along with @Control.Category@.+--+-- @+-- executable app+-- import:+-- options+-- main-is:+-- Main.hs+-- build-depends:+-- base, miso+-- mixins:+-- miso,+-- miso (Miso.Prelude as Prelude),+-- base hiding (Prelude)+-- default-language:+-- Haskell2010+-- @+--+----------------------------------------------------------------------------+module Miso.Prelude+ ( module Miso+ , module Prelude+ , (.)+ ) where+----------------------------------------------------------------------------+import Control.Category ((.))+import Prelude hiding ((.), (!!))+import Miso+----------------------------------------------------------------------------
+ src/Miso/Property.hs view
@@ -0,0 +1,83 @@+-----------------------------------------------------------------------------+{-# LANGUAGE OverloadedStrings #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Property+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- Construct custom properties on DOM elements.+--+-- > div_ [ prop "id" "foo" ] [ ]+--+----------------------------------------------------------------------------+module Miso.Property+ ( -- *** Smart constructors+ prop+ , classList+ , textProp+ , stringProp+ , boolProp+ , intProp+ , integerProp+ , doubleProp+ , objectProp+ , keyProp+ , key_+ ) where+-----------------------------------------------------------------------------+import Miso.JSON (ToJSON(..), Object)+-----------------------------------------------------------------------------+import Miso.Types+-----------------------------------------------------------------------------+-- | @prop k v@ is an attribute that will set the attribute @k@ of the DOM+-- node associated with the vnode to @v@.+prop :: ToJSON a => MisoString -> a -> Attribute action+prop k v = Property k (toJSON v)+-----------------------------------------------------------------------------+-- | Set field to 'Bool' value+boolProp :: MisoString -> Bool -> Attribute action+boolProp = prop+-----------------------------------------------------------------------------+-- | Set field to 'String' value+stringProp :: MisoString -> String -> Attribute action+stringProp = prop+-----------------------------------------------------------------------------+-- | Set field to 'MisoString' value+textProp :: MisoString -> MisoString -> Attribute action+textProp = prop+-----------------------------------------------------------------------------+-- | Set field to t'Object' value+objectProp :: MisoString -> Object -> Attribute action+objectProp = prop+-----------------------------------------------------------------------------+-- | Set field to 'Int' value+intProp :: MisoString -> Int -> Attribute action+intProp = prop+-----------------------------------------------------------------------------+-- | Set field to 'Integer' value+integerProp :: MisoString -> Integer -> Attribute action+integerProp = prop+-----------------------------------------------------------------------------+-- | Set field to 'Double' value+doubleProp :: MisoString -> Double -> Attribute action+doubleProp = prop+-----------------------------------------------------------------------------+-- | Set 'Miso.Types.Key' on 'VNode'.+keyProp :: ToKey key => key -> Attribute action+keyProp key = prop "key" (toKey key)+-----------------------------------------------------------------------------+-- | Synonym for 'keyProp'+-- Allows a user to specify a t'Key' inside of an '[Attribute action]'+key_ :: ToKey key => key -> Attribute action+key_ = keyProp+-----------------------------------------------------------------------------+-- | Smart constructor for specifying 'class'+--+-- @since 1.9.0.0+classList :: [MisoString] -> Attribute action+classList = ClassList+-----------------------------------------------------------------------------
+ src/Miso/PubSub.hs view
@@ -0,0 +1,22 @@+-----------------------------------------------------------------------------+-- |+-- Module : Miso.PubSub+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- Publish / Subscribe primitives for communication between components.+----------------------------------------------------------------------------+module Miso.PubSub+ ( -- ** Publishers / Subscribers+ subscribe+ , unsubscribe+ , publish+ , Topic+ , topic+ ) where+----------------------------------------------------------------------------+import Miso.Runtime+----------------------------------------------------------------------------
+ src/Miso/Random.hs view
@@ -0,0 +1,89 @@+-----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Random+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- A PRNG for use in Component and the Component test infrastructure.+--+-- Uses the splitmix32 algorithm under the hood.+--+----------------------------------------------------------------------------+module Miso.Random+ ( -- ** Types+ StdGen (..)+ , Seed+ -- ** Functions+ , newStdGen+ , mkStdGen+ , next+ , replicateRM+ , getStdGen+ , setStdGen+ -- ** Globals+ , globalStdGen+ ) where+-----------------------------------------------------------------------------+import Data.Tuple (swap)+import Control.Monad.State (state, runState)+import Control.Monad (replicateM)+import Data.IORef+import System.IO.Unsafe (unsafePerformIO)+-----------------------------------------------------------------------------+import Miso.DSL+import qualified Miso.FFI.Internal as FFI+-----------------------------------------------------------------------------+-- | t'StdGen' holds a JS t'Function'.+newtype StdGen = StdGen Function+-----------------------------------------------------------------------------+-- | An initial 'Seed' value, useful for simulations or reproducing test failures+type Seed = Int+-----------------------------------------------------------------------------+-- | Like 'Miso.Random.newStdGen' but takes a t'Seed' as an argument and is pure.+mkStdGen :: Seed -> StdGen+mkStdGen seed = StdGen $ Function $ unsafePerformIO $ FFI.splitmix32 (fromIntegral seed)+-----------------------------------------------------------------------------+-- | Create a new t'StdGen', defaulting to a random t'Seed'.+newStdGen :: IO StdGen+newStdGen = do+ seed <- FFI.getRandomValue+ StdGen . Function <$> FFI.splitmix32 seed+-----------------------------------------------------------------------------+-- | Get the next t'StdGen', extracting the value, useful with t'State'.+next :: StdGen -> (Double, StdGen)+next (StdGen func) = unsafePerformIO $ do+ result <- apply func ()+ pure (result, StdGen func)+-----------------------------------------------------------------------------+-- | Global 'StdGen', used by 'replicateRM' and others.+globalStdGen :: IORef StdGen+{-# NOINLINE globalStdGen #-}+globalStdGen = unsafePerformIO $ do+ seed <- floor . (*1e7) <$> FFI.mathRandom+ newIORef (mkStdGen seed)+-----------------------------------------------------------------------------+-- | Read the `globalStdGen`+getStdGen :: IO StdGen+getStdGen = readIORef globalStdGen+-----------------------------------------------------------------------------+-- | Set the `globalStdGen`+setStdGen :: StdGen -> IO ()+setStdGen = atomicWriteIORef globalStdGen+-----------------------------------------------------------------------------+-- | Generate n amount of random numbers. Uses the global PRNG 'globalStdGen'.+--+-- @+-- replicateRM 10 :: IO [Double]+-- @+--+replicateRM :: Int -> IO [Double]+replicateRM n = do+ atomicModifyIORef globalStdGen $ \gen -> do+ swap $ flip runState gen $ replicateM n (state next)+-----------------------------------------------------------------------------
+ src/Miso/Reload.hs view
@@ -0,0 +1,195 @@+-----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE OverloadedStrings #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Reload+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- Support for live reloading of miso applications.+--+-- = Live Reload+--+-- This module exposes two functions meant to be used during interactive+-- development with GHC WASM browser mode, 'live' and 'reload'.+--+-- == Reload+--+-- Use 'reload' if you'd like to redraw the page on each file change, resetting+-- the working application state.+--+-- @+-- main :: IO ()+-- main = 'reload' 'defaultEvents' app+-- @+--+-- == Live+--+-- Use 'live' if you'd like to persist the working application state (all 'Component' 'model')+-- between GHCi reloads. This only works if you do not alter the 'model' schema (e.g. add, remove, change a field's type).+--+-- @+-- main :: IO ()+-- main = 'live' 'defaultEvents' app+-- @+--+-- See the [miso-sampler](https://github.com/haskell-miso/miso-sampler) for example usage.+--+----------------------------------------------------------------------------+module Miso.Reload+ ( -- ** Functions+ reload+ , live+ ) where+-----------------------------------------------------------------------------+import Control.Monad+#if __GLASGOW_HASKELL__ > 865+import GHC.Conc.Sync (threadLabel)+import GHC.Conc (listThreads, killThread)+#endif+-----------------------------------------------------------------------------+#ifdef WASM+import Miso.DSL.TH.File (evalFile)+#endif+import Miso.DSL ((!), jsg, setField)+import qualified Miso.FFI.Internal as FFI+import Miso.Types (Component(..), Events, App)+import Miso.String (MisoString)+import Miso.Runtime (componentModel, initComponent, topLevelComponentId, resetComponentState, Hydrate(..))+import Miso.Runtime.Internal (components)+-----------------------------------------------------------------------------+import Miso.Lens+-----------------------------------------------------------------------------+import qualified Data.IntMap.Strict as IM+import Data.IORef+import Foreign hiding (void)+import Foreign.C.Types+-----------------------------------------------------------------------------+foreign import ccall unsafe "x_store"+ x_store :: StablePtr a -> IO ()+-----------------------------------------------------------------------------+foreign import ccall unsafe "x_get"+ x_get :: IO (StablePtr a)+-----------------------------------------------------------------------------+foreign import ccall unsafe "x_exists"+ x_exists :: IO CInt+-----------------------------------------------------------------------------+foreign import ccall unsafe "x_clear"+ x_clear :: IO ()+-----------------------------------------------------------------------------+#define MISO_JS_PATH "js/miso.js"+-----------------------------------------------------------------------------+-- | Clears the \<body\> and \<head\> on each 'reload'.+--+-- Meant to be used with WASM browser mode.+--+-- @+-- main :: IO ()+-- main = 'reload' 'defaultEvents' app+-- @+--+-- N.B. This also resets the internal 'component' state. This means all currently+-- mounted components become unmounted and t'ComponentId' are reset to their+-- original form factory.+--+-- If you'd like to preserve application state between calls to GHCi `:r`, see 'live'.+--+-- @since 1.9.0.0+reload+ :: Eq model+ => Events+ -> App model action+ -> IO ()+reload events vcomp = do+#ifdef WASM+ $(evalFile MISO_JS_PATH)+#endif+ resetComponentState clearPage+#if __GLASGOW_HASKELL__ > 865+ threads <- listThreads+ forM_ threads $ \threadId -> do+ threadLabel threadId >>= \case+ Just "scheduler" ->+ killThread threadId+ _ -> pure ()+#endif+ initComponent events Draw vcomp+-----------------------------------------------------------------------------+-- | Live reloading. Persists all t'Component' `model` between successive GHCi reloads.+--+-- This means application state should persist between GHCi reloads +--+-- Schema changes to 'model' are currently unsupported. If you're +-- changing fields in 'model' (adding, removing, changing a field's type), this+-- will more than likely segfault. If you change the 'view' or 'update' functions+-- it will be fine. +--+-- Use 'reload' if you're changing the 'model' frequently and 'live'+-- if you're adjusting the 'view' / 'update' function logic.+--+-- @+-- main :: IO ()+-- main = 'live' 'defaultEvents' app+-- @+--+-- @since 1.9.0.0+live+ :: Eq model+ => Events+ -> App model action+ -> IO ()+live events vcomp = do+ exists <- x_exists+ if exists == 1+ then do+#if __GLASGOW_HASKELL__ > 865+ threads <- listThreads+ forM_ threads $ \threadId -> do+ threadLabel threadId >>= \case+ Just "scheduler" ->+ killThread threadId+ _ -> pure ()+#endif+ -- clearPage (perform this with the context)+ clearPage++ -- Deref old state, update new state, set pointer in C heap.+ _oldState <- readIORef =<< deRefStablePtr =<< x_get++ let oldModel = (_oldState IM.! topLevelComponentId) ^. componentModel+ initialVComp = vcomp { model = oldModel }++ -- Overwrite new components state with old components state+ atomicWriteIORef components _oldState++ -- Perform initial draw, this will fetch the model from the old component state+ -- and overwrite the old state with the new state for everything else.+ initComponent events Draw initialVComp+ + -- Don't forget to flush (native mobile needs this too)+ FFI.flush++ -- Clear and set static ptr to use new state+ x_clear+ x_store =<< newStablePtr components+ else do+ -- This means it is initial load, just store the pointer.+#ifdef WASM+ $(evalFile MISO_JS_PATH)+#endif+ x_store =<< newStablePtr components+ void (initComponent events Draw vcomp)+-----------------------------------------------------------------------------+clearPage :: IO ()+clearPage = do+ body_ <- jsg "document" ! ("body" :: MisoString)+ setField body_ "innerHTML" ("" :: MisoString)+ head_ <- jsg "document" ! ("head" :: MisoString)+ setField head_ "innerHTML" ("" :: MisoString)+-----------------------------------------------------------------------------
src/Miso/Router.hs view
@@ -1,222 +1,601 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE DeriveFunctor #-}+----------------------------------------------------------------------------- {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE PolyKinds #-} ----------------------------------------------------------------------------- -- | -- Module : Miso.Router--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable-----------------------------------------------------------------------------+--+-- This module introduces a 'Router' that produces "correct-by-construction" URL+-- encoding and decoding from any Haskell algebraic data type. This @Router@ can be used+-- in conjunction with 'Miso.Subscription.History.uriSub' or 'Miso.Subscription.History.routerSub'+-- to perform client-side routing. Further+-- it also supports the construction of type-safe links in any @View model action@ via+-- the 'href_' function exported from this module.+--+-- This module can be used in two ways, one is the manual construction of a @Router@+-- as seen below.+--+-- @+--+-- data Route = Widget Int+-- deriving (Show, Eq)+--+-- instance Router Route where+-- routeParser = routes [ Widget \<$\> (path "widget" *\> capture) ]+-- fromRoute (Widget value) = [ toPath "widget", toCapture value ]+--+-- main :: IO ()+-- main = print (runRouter "\/widget\/10" router)+--+-- > Right (Widget "widget" 10)+-- @+--+-- The second way is using the @Generic@ deriving mechanism. This should ensure that+--+-- @+--+-- {-# LANGUAGE DerivingStrategies #-}+-- {-# LANGUAGE DeriveAnyClass #-}+-- {-# LANGUAGE DeriveGeneric #-}+--+-- data Route+-- = About+-- | Home+-- | Widget (Capture "thing" Int) (Path "foo") (Capture "other" MisoString) (QueryParam "bar" Int)+-- deriving stock (Generic, Show)+-- deriving anyclass Router+-- @+--+-- The @Generic@ deriving works by converting the constructor name to a path so+--+-- > test :: Either RoutingError Route+-- > test = toRoute "/widget/23/foo/okay?bar=0"+--+-- Decodes as+--+-- > Right (Widget (Capture 23) (Path "foo") (Capture "okay") (QueryParam (Just 0)))+--+-- The order of t`Capture` and t`Path` matters when defined on your sum type. The order of t`QueryParam` and t`QueryFlag` does not.+--+-- The router is "reversible" which means it can produce type-safe links using the `href_` function.+--+-- > prettyRoute $ Widget (Capture 23) (Path ("foo")) (Capture ("okay")) (QueryParam (Just 0))+-- > "/widget/23/foo/okay?bar=0"+--+-- This can be used in conjunction with the @href_@ field below to embed type safe links into 'Miso.miso' @View model action@ code.+--+-- > button_ [ Miso.Router.href_ (Widget 10) ] [ "click me" ]+--+-- Note: the 'Miso.Router.Index' constructor is name special, it is used to encode the `"/"` path.+--+-- @+--+-- data Route = Index+-- deriving stock (Show, Eq)+-- deriving anyclass (Router)+--+-- main :: IO ()+-- main = print (fromRoute Index)+--+-- -- "/"+-- @+--+-- Lastly, camel-case constructors only use the first hump of the camel.+--+-- @+--+-- data Route = Index | FooBar+-- deriving anyclass Router+-- deriving stock (Show, Eq, Generic)+--+-- main :: IO ()+-- main = print (prettyRoute FooBar)+--+-- "/foo"+-- @+--+----------------------------------------------------------------------------- module Miso.Router- ( runRoute- , route- , HasRouter- , RouteT+ ( -- ** Classes+ Router (..)+ , RouteParser+ , GRouter (..)+ -- ** Types+ , Capture (..)+ , Path (..)+ , QueryParam (..)+ , QueryFlag (..)+ , Token (..)+ , URI (..)+ -- ** Errors , RoutingError (..)+ -- ** Functions+ , parseURI+ , prettyURI+ , prettyQueryString+ -- ** Manual Routing+ , runRouter+ , routes+ -- ** Construction+ , toQueryParam+ , toCapture+ , toPath+ , emptyURI+ -- ** Parser combinators+ , queryFlag+ , queryParam+ , capture+ , path+ -- ** Lexing+ , lexTokens+ , tokensToURI ) where--import qualified Data.ByteString.Char8 as BS+-----------------------------------------------------------------------------+import qualified Data.Map.Strict as M+import Data.Maybe+import Data.Functor import Data.Proxy-import Data.Text (Text)-import qualified Data.Text as T-import Data.Text.Encoding+import qualified Data.Char as C+import Data.String+import Control.Applicative+import Control.Monad+import GHC.Generics import GHC.TypeLits-import Network.HTTP.Types hiding (Header)-import Network.URI-import Servant.API-import Web.HttpApiData--import Miso.Html hiding (text)---- | Router terminator.--- The 'HasRouter' instance for 'View' finalizes the router.------ Example:------ > type MyApi = "books" :> Capture "bookId" Int :> View---- | 'Location' is used to split the path and query of a URI into components.-data Location = Location- { locPath :: [Text]- , locQuery :: Query- } deriving (Show, Eq, Ord)---- | When routing, the router may fail to match a location.-data RoutingError = Fail- deriving (Show, Eq, Ord)---- | A 'Router' contains the information necessary to execute a handler.-data Router a where- RChoice :: Router a -> Router a -> Router a- RCapture :: FromHttpApiData x => (x -> Router a) -> Router a- RQueryParam :: (FromHttpApiData x, KnownSymbol sym)- => Proxy sym -> (Maybe x -> Router a) -> Router a- RQueryParams :: (FromHttpApiData x, KnownSymbol sym)- => Proxy sym -> ([x] -> Router a) -> Router a- RQueryFlag :: KnownSymbol sym- => Proxy sym -> (Bool -> Router a) -> Router a- RPath :: KnownSymbol sym => Proxy sym -> Router a -> Router a- RPage :: a -> Router a---- | This is similar to the @HasServer@ class from @servant-server@.--- It is the class responsible for making API combinators routable.--- 'RouteT' is used to build up the handler types.--- 'Router' is returned, to be interpretted by 'routeLoc'.-class HasRouter layout where- -- | A mkRouter handler.- type RouteT layout a :: *- -- | Transform a mkRouter handler into a 'Router'.- mkRouter :: Proxy layout -> Proxy a -> RouteT layout a -> Router a---- | Alternative-instance (HasRouter x, HasRouter y) => HasRouter (x :<|> y) where- type RouteT (x :<|> y) a = RouteT x a :<|> RouteT y a- mkRouter _ (a :: Proxy a) ((x :: RouteT x a) :<|> (y :: RouteT y a))- = RChoice (mkRouter (Proxy :: Proxy x) a x) (mkRouter (Proxy :: Proxy y) a y)---- | Capture-instance (HasRouter sublayout, FromHttpApiData x) =>- HasRouter (Capture sym x :> sublayout) where- type RouteT (Capture sym x :> sublayout) a = x -> RouteT sublayout a- mkRouter _ a f = RCapture (\x -> mkRouter (Proxy :: Proxy sublayout) a (f x))---- | QueryParam-instance (HasRouter sublayout, FromHttpApiData x, KnownSymbol sym)- => HasRouter (QueryParam sym x :> sublayout) where- type RouteT (QueryParam sym x :> sublayout) a = Maybe x -> RouteT sublayout a- mkRouter _ a f = RQueryParam (Proxy :: Proxy sym)- (\x -> mkRouter (Proxy :: Proxy sublayout) a (f x))---- | QueryParams-instance (HasRouter sublayout, FromHttpApiData x, KnownSymbol sym)- => HasRouter (QueryParams sym x :> sublayout) where- type RouteT (QueryParams sym x :> sublayout) a = [x] -> RouteT sublayout a- mkRouter _ a f = RQueryParams- (Proxy :: Proxy sym)- (\x -> mkRouter (Proxy :: Proxy sublayout) a (f x))---- | QueryFlag-instance (HasRouter sublayout, KnownSymbol sym)- => HasRouter (QueryFlag sym :> sublayout) where- type RouteT (QueryFlag sym :> sublayout) a = Bool -> RouteT sublayout a- mkRouter _ a f = RQueryFlag- (Proxy :: Proxy sym)- (\x -> mkRouter (Proxy :: Proxy sublayout) a (f x))---- | Header-instance HasRouter sublayout => HasRouter (Header sym (x :: *) :> sublayout) where- type RouteT (Header sym x :> sublayout) a = Maybe x -> RouteT sublayout a- mkRouter _ a f = mkRouter (Proxy :: Proxy sublayout) a (f Nothing)---- | Path-instance (HasRouter sublayout, KnownSymbol path)- => HasRouter (path :> sublayout) where- type RouteT (path :> sublayout) a = RouteT sublayout a- mkRouter _ a page = RPath- (Proxy :: Proxy path)- (mkRouter (Proxy :: Proxy sublayout) a page)---- | View-instance HasRouter (View a) where- type RouteT (View a) x = x- mkRouter _ _ a = RPage a+-----------------------------------------------------------------------------+import Miso.Types hiding (model)+import Miso.Util+import qualified Miso.Html.Property as P+import Miso.Util.Parser hiding (NoParses)+import qualified Miso.Util.Lexer as L+import Miso.Util.Lexer (Lexer)+import Miso.String (ToMisoString, FromMisoString, fromMisoStringEither)+import qualified Miso.String as MS+-----------------------------------------------------------------------------+-- | Type used for representing capture variables+newtype Capture sym a = Capture a+ deriving stock (Eq, Show)+ deriving newtype (ToMisoString, FromMisoString)+-----------------------------------------------------------------------------+-- | Type used for representing URL paths+newtype Path (path :: Symbol) = Path MisoString+ deriving stock (Eq, Show)+ deriving newtype (ToMisoString, IsString)+-----------------------------------------------------------------------------+-- | Type used for representing query flags+newtype QueryFlag (path :: Symbol) = QueryFlag Bool+ deriving stock (Eq, Show)+-----------------------------------------------------------------------------+-- | Type used for representing query parameters+newtype QueryParam (path :: Symbol) a = QueryParam (Maybe a)+ deriving stock (Eq, Show)+-----------------------------------------------------------------------------+instance (ToMisoString a, KnownSymbol path) => ToMisoString (QueryParam path a) where+ toMisoString (QueryParam maybeVal) =+ maybe mempty (\param -> "?" <> param <> "=" <> val) (ms <$> maybeVal)+ where+ val = ms $ symbolVal (Proxy @path)+-----------------------------------------------------------------------------+instance (FromMisoString a, KnownSymbol path) => FromMisoString (QueryParam path a) where+ fromMisoStringEither x =+ case fromMisoStringEither @a x of+ Right r -> Right $ QueryParam (Just r)+ Left v -> Left v+-----------------------------------------------------------------------------+instance KnownSymbol name => ToMisoString (QueryFlag name) where+ toMisoString = \case+ QueryFlag True ->+ "?" <> ms (symbolVal (Proxy @name))+ QueryFlag False ->+ mempty+-----------------------------------------------------------------------------+-- | A list of tokens are returned from a successful lex of a t'URI'+data Token+ = QueryParamTokens [(MisoString, Maybe MisoString)]+ | QueryParamToken MisoString (Maybe MisoString)+ | CaptureOrPathToken MisoString+ | FragmentToken MisoString+ | IndexToken+ deriving (Show, Eq)+-----------------------------------------------------------------------------+-- | Smart constructor for building a 'QueryParamToken'+toQueryParam :: ToMisoString s => MisoString -> s -> Token+toQueryParam k v = QueryParamToken k (Just (ms v))+-----------------------------------------------------------------------------+-- | Smart constructor for building a capture variable+toCapture :: ToMisoString string => string -> Token+toCapture = CaptureOrPathToken . ms+-----------------------------------------------------------------------------+-- | Smart constructor for building a path fragment+toPath :: MisoString -> Token+toPath = CaptureOrPathToken+-----------------------------------------------------------------------------+-- | Converts a list of @[Token]@ into an actual @URI@.+tokensToURI :: [Token] -> URI+tokensToURI tokens = URI+ { uriPath =+ case tokens of+ IndexToken : _ -> ""+ _ ->+ MS.intercalate "/"+ [ x+ | CaptureOrPathToken x <- filter isPathRelated tokens+ ]+ , uriQueryString =+ M.unions+ [ case queryToken of+ QueryParamTokens queryParams_ ->+ M.fromList queryParams_+ QueryParamToken k v ->+ M.singleton k v+ _ ->+ mempty+ | queryToken <- filter isQuery tokens+ ]+ , uriFragment =+ foldMap ms (filter isFragment tokens)+ } where+ isFragment = \case+ FragmentToken{} -> True+ _ -> False+ isQuery = \case+ QueryParamToken{} -> True+ _ -> False+ isPathRelated = \case+ CaptureOrPathToken {} -> True+ IndexToken {} -> True+ _ -> False+-----------------------------------------------------------------------------+instance ToMisoString Token where+ toMisoString = \case+ CaptureOrPathToken x -> "/" <> x+ FragmentToken x -> "#" <> x+ QueryParamTokens params ->+ "?" <> MS.intercalate "&"+ [ case value of+ Nothing -> key+ Just v -> key <> "=" <> v+ | (key, value) <- params+ ]+ QueryParamToken k (Just v) ->+ "?" <> k <> "=" <> v+ QueryParamToken k Nothing ->+ "?" <> k+ IndexToken -> "/"+-----------------------------------------------------------------------------+-- | An error that can occur during lexing / parsing of a URI into a user-defined+-- data type+data RoutingError+ = ParseError MisoString [Token]+ | AmbiguousParse MisoString [Token]+ | LexError MisoString MisoString+ | LexErrorEOF MisoString+ | NoParses MisoString+ deriving (Show, Eq)+-----------------------------------------------------------------------------+-- | State monad for parsing URI+type RouteParser = ParserT URI [Token] []+-----------------------------------------------------------------------------+-- | Combinator for parsing a capture variable out of a URI+capture :: FromMisoString value => RouteParser value+capture = do+ CaptureOrPathToken capture_ <- captureOrPathToken+ case fromMisoStringEither capture_ of+ Left msg -> fail (fromMisoString (ms msg))+ Right token -> pure token+-----------------------------------------------------------------------------+-- | Combinator for parsing a path out of a URI+path :: MisoString -> RouteParser MisoString+path specified = do+ CaptureOrPathToken parsed <- captureOrPathToken+ when (specified /= parsed) (fail "path")+ pure specified+-----------------------------------------------------------------------------+index :: MisoString -> RouteParser MisoString+index specified = do+ IndexToken <- indexToken+ when (specified /= "index") (fail "index")+ pure "/"+-----------------------------------------------------------------------------+-- | URI parsing+parseURI :: MisoString -> Either MisoString URI+parseURI txt =+ case lexTokens txt of+ Left (L.LexerError err _) -> Left err+ Left (L.UnexpectedEOF eof) -> Left ("EOF: " <> ms (show eof))+ Right tokens -> Right (tokensToURI tokens)+-----------------------------------------------------------------------------+-- | Class used to facilitate routing for miso applications+class Router route where+ fromRoute :: route -> [Token]+ default fromRoute :: (Generic route, GRouter (Rep route)) => route -> [Token]+ fromRoute = gFromRoute . from --- | Verb-instance HasRouter (Verb m s c a) where- type RouteT (Verb m s c a) x = x- mkRouter _ _ a = RPage a+ -- | Convert a 'Router route => route' into a t'URI'+ toURI :: route -> URI+ toURI = tokensToURI . fromRoute --- | Raw-instance HasRouter Raw where- type RouteT Raw x = x- mkRouter _ _ a = RPage a+ -- | Map a URI back to a route+ route :: URI -> Either RoutingError route+ route = toRoute . prettyURI --- | Use a handler to mkRouter a 'Location'.--- Normally 'route' should be used instead, unless you want custom--- handling of string failing to parse as 'URI'.-runRouteLoc :: forall layout a. HasRouter layout- => Location -> Proxy layout -> RouteT layout a -> Either RoutingError a-runRouteLoc loc layout page =- let routing = mkRouter layout (Proxy :: Proxy a) page- in routeLoc loc routing+ -- | Convenience for specifying a URL as a hyperlink reference in 'Miso.Types.View'+ href_ :: route -> Attribute action+ href_ = P.href_ . prettyRoute --- | Use a handler to mkRouter a location, represented as a 'String'.--- All handlers must, in the end, return @m a@.--- 'routeLoc' will choose a mkRouter and return its result.-route- :: HasRouter layout- => Proxy layout- -> RouteT layout a- -> URI- -> Either RoutingError a-route layout handler u = runRouteLoc (uriToLocation u) layout handler+ -- | Route pretty printing+ prettyRoute :: route -> MisoString+ prettyRoute = prettyURI . tokensToURI . fromRoute --- | Executes router-runRoute- :: HasRouter layout- => Proxy layout- -> RouteT layout (m -> a)- -> (m -> URI)- -> m- -> Either RoutingError a-runRoute layout pages getURI model = ($ model) <$> route layout pages (getURI model)+ -- | Route debugging+ dumpURI :: route -> MisoString+ dumpURI = ms . show . tokensToURI . fromRoute --- | Use a computed 'Router' to mkRouter a 'Location'.-routeLoc :: Location -> Router a -> Either RoutingError a-routeLoc loc r = case r of- RChoice a b -> do- case routeLoc loc a of- Left Fail -> routeLoc loc b- Right x -> Right x- RCapture f -> case locPath loc of- [] -> Left Fail- capture:paths ->- case parseUrlPieceMaybe capture of- Nothing -> Left Fail- Just x -> routeLoc loc { locPath = paths } (f x)- RQueryParam sym f -> case lookup (BS.pack $ symbolVal sym) (locQuery loc) of- Nothing -> routeLoc loc (f Nothing)- Just Nothing -> Left Fail- Just (Just text) -> case parseQueryParamMaybe (decodeUtf8 text) of- Nothing -> Left Fail- Just x -> routeLoc loc (f (Just x))- RQueryParams sym f -> maybe (Left Fail) (\x -> routeLoc loc (f x)) $ do- ps <- sequence $ snd <$> Prelude.filter- (\(k, _) -> k == BS.pack (symbolVal sym)) (locQuery loc)- sequence $ (parseQueryParamMaybe . decodeUtf8) <$> ps- RQueryFlag sym f -> case lookup (BS.pack $ symbolVal sym) (locQuery loc) of- Nothing -> routeLoc loc (f False)- Just Nothing -> routeLoc loc (f True)- Just (Just _) -> Left Fail- RPath sym a -> case locPath loc of- [] -> Left Fail- p:paths -> if p == T.pack (symbolVal sym)- then routeLoc (loc { locPath = paths }) a- else Left Fail- RPage a ->- case locPath loc of- [] -> Right a- [""] -> Right a- _ -> Left Fail+ -- | Route parsing from a 'MisoString'+ toRoute :: MisoString -> Either RoutingError route+ toRoute input = parseRoute input routeParser --- | Convert a 'URI' to a 'Location'.-uriToLocation :: URI -> Location-uriToLocation uri = Location- { locPath = decodePathSegments $ BS.pack (uriPath uri)- , locQuery = parseQuery $ BS.pack (uriQuery uri)- }+ routeParser :: RouteParser route+ default routeParser :: (Generic route, GRouter (Rep route)) => RouteParser route+ routeParser = to <$> gRouteParser+-----------------------------------------------------------------------------+-- | Smart constructor for building a @RouteParser@+--+-- @+--+-- data Route = Widget MisoString Int+--+-- instance Router Route where+-- routeParser = routes [ Widget \<$\> path "widget" \<*\> capture ]+-- fromRoute (Widget path value) = [ toPath path, toCapture value ]+--+-- router :: Router router => RouteParser router+-- router = routes [ Widget \<$\> path "widget" \<*\> capture ]+--+-- > Right (Widget "widget" 10)+-- @+--+-----------------------------------------------------------------------------+runRouter :: MisoString -> RouteParser route -> Either RoutingError route+runRouter = parseRoute+-----------------------------------------------------------------------------+-- | Convenience for specifying multiple routes+routes :: [ RouteParser route ] -> RouteParser route+routes = foldr (<|>) empty+-----------------------------------------------------------------------------+-- | Generic deriving for 'Router'+class GRouter f where+ gFromRoute :: f route -> [Token]+ gRouteParser :: RouteParser (f route)+-----------------------------------------------------------------------------+instance GRouter next => GRouter (D1 m next) where+ gFromRoute (M1 x) = gFromRoute x+ gRouteParser = M1 <$> gRouteParser+-----------------------------------------------------------------------------+instance (KnownSymbol name, GRouter next) => GRouter (C1 ('MetaCons name x y) next) where+ gFromRoute (M1 x) =+ case name of+ "index" -> [IndexToken]+ _ -> CaptureOrPathToken name : gFromRoute x+ where+ name = lowercaseStrip $ symbolVal (Proxy @name)+ gRouteParser = do+ case name of+ "index" -> do+ void (index name)+ M1 <$> gRouteParser+ _ -> do+ void (path name)+ M1 <$> gRouteParser+ where+ name = lowercaseStrip $ symbolVal (Proxy @name)+-----------------------------------------------------------------------------+instance GRouter next => GRouter (S1 m next) where+ gFromRoute (M1 x) = gFromRoute x+ gRouteParser = M1 <$> gRouteParser+-----------------------------------------------------------------------------+instance {-# OVERLAPS #-} forall path m . KnownSymbol path => GRouter (K1 m (Path path)) where+ gFromRoute (K1 x) = pure $ CaptureOrPathToken (ms x)+ gRouteParser = K1 (Path chunk) <$ path chunk+ where+ chunk = ms $ symbolVal (Proxy :: Proxy path)+-----------------------------------------------------------------------------+instance {-# OVERLAPS #-} (FromMisoString a, ToMisoString a) => GRouter (K1 m (Capture sym a)) where+ gFromRoute (K1 x) = pure $ CaptureOrPathToken (ms x)+ gRouteParser = K1 <$> capture+-----------------------------------------------------------------------------+instance {-# OVERLAPS #-} forall param m a . (ToMisoString a, FromMisoString a, KnownSymbol param) =>+ GRouter (K1 m (QueryParam param a)) where+ gFromRoute (K1 (QueryParam maybeParam)) = do+ let key = ms (symbolVal (Proxy @param))+ case maybeParam of+ Nothing -> [QueryParamToken key Nothing]+ Just v -> [QueryParamToken key (Just (ms v))]+ gRouteParser = K1 <$> queryParam+-----------------------------------------------------------------------------+-- | Query parameter parser from a route+queryParam+ :: forall param a . (FromMisoString a, KnownSymbol param)+ => RouteParser (QueryParam param a)+queryParam = do+ URI {..} <- askParser+ QueryParam <$> do+ case M.lookup (ms (symbolVal (Proxy @param))) uriQueryString of+ Just (Just value) ->+ case fromMisoStringEither value of+ Left _ -> pure Nothing+ Right parsed -> pure (Just parsed)+ _ -> pure Nothing+-----------------------------------------------------------------------------+instance {-# OVERLAPS #-} forall flag m . KnownSymbol flag => GRouter (K1 m (QueryFlag flag)) where+ gFromRoute (K1 (QueryFlag specified))+ | specified = [ QueryParamToken flag Nothing ]+ | otherwise = []+ where+ flag = ms (symbolVal (Proxy @flag))+ gRouteParser = K1 <$> queryFlag+-----------------------------------------------------------------------------+-- | Query flag parser from a route+queryFlag :: forall flag . KnownSymbol flag => RouteParser (QueryFlag flag)+queryFlag = do+ URI {..} <- askParser+ pure $ QueryFlag $ isJust (M.lookup flag uriQueryString)+ where+ flag = ms $ symbolVal (Proxy @flag)+-----------------------------------------------------------------------------+instance Router a => GRouter (K1 m a) where+ gFromRoute (K1 x) = fromRoute x+ gRouteParser = K1 <$> routeParser+-----------------------------------------------------------------------------+instance GRouter U1 where+ gFromRoute U1 = []+ gRouteParser = pure U1+-----------------------------------------------------------------------------+instance (GRouter left, GRouter right) => GRouter (left :*: right) where+ gFromRoute (left :*: right) = gFromRoute left <> gFromRoute right+ gRouteParser = liftA2 (:*:) gRouteParser gRouteParser+-----------------------------------------------------------------------------+instance (GRouter left, GRouter right) => GRouter (left :+: right) where+ gFromRoute = \case+ L1 m1 -> gFromRoute m1+ R1 m1 -> gFromRoute m1+ gRouteParser = foldr (<|>) empty+ [ L1 <$> gRouteParser+ , R1 <$> gRouteParser+ ]+-----------------------------------------------------------------------------+captureOrPathToken :: RouteParser Token+captureOrPathToken = satisfy $ \case+ CaptureOrPathToken {} -> True+ _ -> False+-----------------------------------------------------------------------------+indexToken :: RouteParser Token+indexToken = satisfy $ \case+ IndexToken {} -> True+ _ -> False+-----------------------------------------------------------------------------+-- | Lexing for a URI+uriLexer :: Lexer [Token]+uriLexer = do+ tokens <- some lexer+ void $ optional (L.char '/')+ pure (postProcess tokens)+ where+ postProcess :: [Token] -> [Token]+ postProcess = concatMap $ \case+ QueryParamTokens queryParams_ ->+ [ QueryParamToken k v+ | (k,v) <- queryParams_+ ]+ x -> pure x+ lexer = msum+ [ captureOrPathLexer+ , queryParamLexer+ , fragmentLexer+ , indexLexer+ ] where+ indexLexer =+ IndexToken <$ L.char '/'+ captureOrPathLexer = do+ void (L.char '/')+ CaptureOrPathToken <$> chars+ fragmentLexer = do+ void (L.char '#')+ FragmentToken <$> fragment+ queryParamLexer = QueryParamTokens <$> do+ void (L.char '?')+ sepBy (L.char '&') $ do+ key <- query+ maybeValue <-+ optional $ do+ void (L.char '=')+ query+ pure (key, maybeValue)+-----------------------------------------------------------------------------+chars :: Lexer MisoString+chars = MS.concat <$> some pchar+-----------------------------------------------------------------------------+pchar :: Lexer MisoString+pchar = unreserved <|> pctEncoded <|> subDelims <|> L.string ":" <|> L.string "@"+-----------------------------------------------------------------------------+fragment :: Lexer MisoString+fragment = query+-----------------------------------------------------------------------------+query :: Lexer MisoString+query = foldr (<|>) empty+ [ MS.concat <$> some pchar+ ]+-----------------------------------------------------------------------------+subDelims :: Lexer MisoString+subDelims = fmap ms <$> L.satisfy $ \x -> x `elem` ("!$'()*+,;" :: String)+-----------------------------------------------------------------------------+unreserved :: Lexer MisoString+unreserved = ms <$> do+ L.satisfy $ \x -> or+ [ C.isAlphaNum x+ , x == '-'+ , x == '.'+ , x == '_'+ , x == '~'+ ]+-----------------------------------------------------------------------------+pctEncoded :: Lexer MisoString+pctEncoded = do+ pct <- L.char '%'+ d1 <- hexDig+ d2 <- hexDig+ pure (ms pct <> ms d1 <> ms d2)+-----------------------------------------------------------------------------+hexDig :: Lexer Char+hexDig = L.satisfy C.isHexDigit+-----------------------------------------------------------------------------+lexTokens :: MisoString -> Either L.LexerError [Token]+lexTokens input =+ case L.runLexer uriLexer (L.mkStream input) of+ Right (tokens, _) -> Right tokens+ Left x -> Left x+-----------------------------------------------------------------------------+parseRoute :: MisoString -> RouteParser a -> Either RoutingError a+parseRoute input parser =+ case L.runLexer uriLexer (L.mkStream input) of+ Left (L.LexerError lexErrorMessage _) ->+ Left (LexError input lexErrorMessage)+ Left (L.UnexpectedEOF _) ->+ Left (LexErrorEOF input)+ Right (tokens, _) -> do+ let+ uri = tokensToURI tokens+ isCapturePathOrIndex = \case+ CaptureOrPathToken{} -> True+ IndexToken{} -> True+ _ -> False+ case runParserT parser uri (filter isCapturePathOrIndex tokens) of+ [(x, [])] ->+ Right x+ [(_, leftovers)] ->+ Left $ ParseError input leftovers+ [] ->+ Left $ NoParses input+ (_, leftovers) : _ ->+ Left $ AmbiguousParse input leftovers+-----------------------------------------------------------------------------+lowercaseStrip :: String -> MisoString+lowercaseStrip (x:xs) = ms (C.toLower x : takeWhile C.isLower xs)+lowercaseStrip x = ms x+-----------------------------------------------------------------------------
+ src/Miso/Runtime.hs view
@@ -0,0 +1,1842 @@+-----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NumericUnderscores #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+-----------------------------------------------------------------------------+{-# OPTIONS_GHC -fno-warn-orphans #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Runtime+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+-----------------------------------------------------------------------------+module Miso.Runtime+ ( -- * Internal functions+ initialize+ , freshComponentId+ , buildVTree+ , renderStyles+ , renderScripts+ , Hydrate(..)+ -- * Subscription+ , startSub+ , stopSub+ -- * Pub / Sub+ , subscribe+ , unsubscribe+ , publish+ , Topic (..)+ , topic+ -- * Component+ , ComponentState (..)+ -- ** Communication+ , mail+ , checkMail+ , broadcast+ , parent+ , mailParent+ -- ** WebSocket+ , websocketConnect+ , websocketConnectJSON+ , websocketConnectText+ , websocketConnectArrayBuffer+ , websocketConnectBLOB+ , websocketSend+ , websocketClose+ , socketState+ , emptyWebSocket+ , WebSocket (..)+ , URL+ , SocketState (..)+ , CloseCode (..)+ , Closed (..)+ -- ** EventSource+ , eventSourceConnectText+ , eventSourceConnectJSON+ , eventSourceClose+ , emptyEventSource+ , EventSource (..)+ -- ** Payload+ , Payload (..)+ , json+ , blob+ , arrayBuffer+ -- ** Internal Component state+ , components+ , componentIds+ , rootComponentId+ , componentId+ , modifyComponent+ , resetComponentState+ , componentModel+ -- ** Scheduler+ , scheduler+#ifdef WASM+ , evalFile+#endif+ , topLevelComponentId+ , initComponent+ , withJS+ ) where+-----------------------------------------------------------------------------+import qualified Data.IntSet as IS+import Data.IntSet (IntSet)+import Control.Category ((.))+import Control.Concurrent+import Control.Exception (SomeException, catch, evaluate)+import Control.Monad (forM, forM_, when, void, (<=<), zipWithM_, forever, foldM)+import Control.Monad.Reader (ask, asks)+import Control.Monad.State hiding (state)+import Miso.JSON (FromJSON, ToJSON, Result(..), fromJSON, toJSON)+import Data.Foldable (toList)+import qualified Data.List as List+import Data.Maybe+import Data.Map.Strict (Map)+import qualified Data.Map.Strict as M+import Data.IntMap.Strict (IntMap)+import qualified Data.IntMap.Strict as IM+import Data.IORef (IORef, newIORef, atomicModifyIORef', readIORef, atomicWriteIORef)+import qualified Data.Sequence as S+import Data.Sequence (Seq)+#if __GLASGOW_HASKELL__ > 865+import GHC.Conc (labelThread)+#endif+import GHC.Conc (ThreadStatus(ThreadDied, ThreadFinished), threadStatus)+import Prelude hiding ((.))+import System.IO.Unsafe (unsafePerformIO)+import System.Mem.StableName (makeStableName)+#ifdef BENCH+import Text.Printf+#endif+import Unsafe.Coerce (unsafeCoerce)+-----------------------------------------------------------------------------+import Miso.Concurrent (Waiter(..), waiter)+import Miso.CSS (renderStyleSheet)+import Miso.Delegate (delegator)+import qualified Miso.Diff as Diff+import Miso.DSL+#ifdef WASM+import Miso.DSL.TH.File (evalFile)+#endif+import Miso.Effect+ ( ComponentInfo(..), Sub, Sink, Effect, Schedule(..), runEffect+ , io_, withSink, Synchronicity(..)+ )+import qualified Miso.FFI.Internal as FFI+import Miso.FFI.Internal (Blob(..), ArrayBuffer(..))+import qualified Miso.Hydrate as Hydrate+import Miso.JSON (encode, jsonStringify, Value)+import Miso.Lens hiding (view)+import Miso.String (ToMisoString(..))+import Miso.Types+import Miso.Util+-----------------------------------------------------------------------------+-- | Helper function to abstract out initialization of t'Miso.Types.Component' between top-level API functions.+initialize+ :: (Eq parent, Eq model)+ => Events+ -> ComponentId+ -> Hydrate+ -> Bool+ -- ^ Is the root node being rendered?+ -> Component parent model action+ -> IO DOMRef+ -- ^ Callback function is used for obtaining the t'Miso.Types.Component' 'DOMRef'.+ -> IO (ComponentState parent model action)+initialize events _componentParentId hydrate isRoot comp@Component {..} getComponentMountPoint = do+ _componentId <- freshComponentId+ let+ _componentSink = \action -> liftIO $ do+ atomicModifyIORef' globalQueue (\q -> (enqueue _componentId action q, ()))+ notify globalWaiter++ initializedModel <-+ case (hydrate, hydrateModel) of+ (Hydrate, Just m) -> m+ (Draw, _) -> do+ IM.lookup _componentId <$> readIORef components >>= \case+ Nothing ->+ pure model+ Just cs ->+ -- hot reload scenario, let it flow+ pure (cs ^. componentModel)+ _ -> pure model+ _componentScripts <- (++) <$> renderScripts scripts <*> renderStyles styles+ _componentDOMRef <- getComponentMountPoint+ _componentIsDirty <- pure False+ _componentVTree <- liftIO $ newIORef (VTree (Object jsNull))+ _componentSubThreads <- liftIO (newIORef M.empty)++ frame <- newEmptyMVar :: IO (MVar Double)+ _componentModel <- liftIO (pure initializedModel)+ _componentMailbox <- pure S.empty++ rAFCallback <-+ asyncCallback1 $ \jsval -> do+ putMVar frame =<< fromJSValUnchecked jsval++ let _componentDraw = \newModel -> do+ newVTree <- buildVTree events _componentParentId _componentId Draw _componentSink logLevel (view newModel)+ oldVTree <- liftIO (readIORef _componentVTree)+ _frame <- requestAnimationFrame rAFCallback+ _timestamp :: Double <- takeMVar frame+ Diff.diff (Just oldVTree) (Just newVTree) _componentDOMRef+ FFI.updateRef oldVTree newVTree+ liftIO (atomicWriteIORef _componentVTree newVTree)+ FFI.flush++ let _componentApplyActions = \(actions :: [action]) model_ comps -> do+ let info = ComponentInfo _componentId _componentParentId _componentDOMRef+ List.foldl' (\(vcomps, m, ss, dirtySet) a ->+ case runEffect (update a) info m of+ (n, sss) ->+ let (newComps, newDirty)+ | modelCheck m n =+ let cs = vcomps IM.! _componentId+ in propagate _componentId+ (IM.insert _componentId (cs { _componentModel = n }) vcomps)+ | otherwise = (vcomps, mempty)+ in (newComps, n, ss <> sss, dirtySet <> newDirty)+ ) (comps, model_, [], mempty) actions++ let vcomponent = ComponentState+ { _componentEvents = events+ , _componentMailbox = mailbox+ , _componentBindings = bindings+ , _componentTopics = mempty+ , _componentModelDirty = modelCheck+ , _componentChildren = mempty+ , ..+ }++ when isRoot (delegator _componentDOMRef _componentVTree events (logLevel `elem` [DebugEvents, DebugAll]))+ registerComponent vcomponent+ initSubs subs _componentSubThreads _componentSink+ initialDraw initializedModel events hydrate isRoot comp vcomponent+ forM_ mount _componentSink+ FFI.mountComponent _componentId =<< toObject jsNull+ pure vcomponent+-----------------------------------------------------------------------------+initSubs :: [Sub action] -> IORef (Map MisoString ThreadId) -> Sink action -> IO ()+initSubs subs_ _componentSubThreads _componentSink = do+ forM_ subs_ $ \sub_ -> do+ threadId <- forkIO (sub_ _componentSink)+ subKey <- liftIO freshSubId+ liftIO $ atomicModifyIORef' _componentSubThreads $ \m ->+ (M.insert subKey threadId m, ())+-----------------------------------------------------------------------------+-- | Diffs two models, returning True if a redraw is necessary+modelCheck :: Eq model => model -> model -> Bool+modelCheck c n = unsafePerformIO $ do+ currentName <- c `seq` makeStableName c+ updatedName <- n `seq` makeStableName n+ pure (currentName /= updatedName && c /= n)+-----------------------------------------------------------------------------+-- | Checks if the Component is mounted before executing actions+isMounted :: ComponentId -> IO Bool+isMounted vcompId = isJust . IM.lookup vcompId <$> readIORef components+-----------------------------------------------------------------------------+-- | The scheduler processes all events in the system and is responsible+-- for propagating changes across model states both asynchronously+-- and synchronously (via 'Binding'). It also is responsible for+-- top-down rendering of the UI Component tree.+scheduler :: IO ()+scheduler =+ forever $ do+ getBatch >>= \case+ Nothing -> wait globalWaiter+ Just (vcompId, actions) -> do+ mounted <- isMounted vcompId+ when mounted (run vcompId actions)+ where+ -----------------------------------------------------------------------------+ -- | Execute the commit phase against the model, perform top-down render+ -- of the entire Component tree.+ run :: ComponentId -> [action] -> IO ()+ run vcompId = renderComponents <=< commit vcompId+ -----------------------------------------------------------------------------+ -- | Apply the actions across the model, evaluate async and sync IO.+ commit :: ComponentId -> [action] -> IO ComponentIds+ commit vcompId events = do+ (updatedModel, schedules, dirtySet, ComponentState{..}) <- do+ atomicModifyIORef' components $ \vcomps -> do+ let cs@ComponentState {..} = vcomps IM.! vcompId+ case _componentApplyActions events _componentModel vcomps of+ (x, updatedModel, schedules, dirtySet) ->+ (x, (updatedModel, schedules, dirtySet, cs))+ forM_ schedules $ \case+ Schedule Async action ->+ evalScheduled Async (action _componentSink)+ Schedule Sync action ->+ evalScheduled Sync (action _componentSink)+ if _componentModelDirty _componentModel updatedModel+ then do+ modifyComponent _componentId $ do+ isDirty .= True+ componentModel .= updatedModel+ pure dirtySet+ else+ pure mempty+ -----------------------------------------------------------------------------+ -- | Perform a top-down rendering of the 'Component' tree.+ --+ -- We lookup the components each time to account for unmounting.+ -- Reset the dirty bit if a render occurs+ --+ renderComponents :: ComponentIds -> IO ()+ renderComponents dirtySet = do+ forM_ (IS.toAscList dirtySet) $ \vcompId ->+ IM.lookup vcompId <$> liftIO (readIORef components) >>= mapM \ComponentState {..} -> do+ when _componentIsDirty $ do+ _componentDraw _componentModel+ FFI.modelHydration _componentId =<< toObject jsNull+ modifyComponent _componentId (isDirty .= False)+-----------------------------------------------------------------------------+-- | Modify a single t'Component p m a' at a t'ComponentId'.+--+-- Auxiliary function+modifyComponent+ :: ComponentId+ -> State (ComponentState parent model action) a+ -> IO ()+modifyComponent vcompId go = liftIO $ do+ atomicModifyIORef' components $ \vcomps ->+ case IM.lookup vcompId vcomps of+ Nothing ->+ (vcomps, ())+ Just comp ->+ (IM.insert vcompId (execState go comp) vcomps, ())+----------------------------------------------------------------------------+propagate+ :: ComponentId+ -> IntMap (ComponentState p m a)+ -> (IntMap (ComponentState p m a), ComponentIds)+propagate vcompId vcomps =+ let dfsState = execState synch (dfs vcomps vcompId)+ in (_state dfsState, _visited dfsState)+-----------------------------------------------------------------------------+-- | Create an empty DFS state+dfs :: IntMap (ComponentState p m a) -> ComponentId -> DFS p m a+dfs cs vcompId = DFS cs mempty (pure vcompId)+-----------------------------------------------------------------------------+type ComponentIds = IntSet+-----------------------------------------------------------------------------+data DFS p m a+ = DFS+ { _state :: IntMap (ComponentState p m a)+ -- ^ global component state to alter+ , _visited :: ComponentIds+ -- ^ visited set+ , _stack :: [ComponentId]+ -- ^ neighbors queue+ }+-----------------------------------------------------------------------------+type Synch p m a x = State (DFS p m a) x+-----------------------------------------------------------------------------+visited :: Lens (DFS p m a) (ComponentIds)+visited = lens _visited $ \r x -> r { _visited = x }+-----------------------------------------------------------------------------+state :: Lens (DFS p m a) (IntMap (ComponentState p m a))+state = lens _state $ \r x -> r { _state = x }+-----------------------------------------------------------------------------+stack :: Lens (DFS p m a) [ComponentId]+stack = lens _stack $ \r x -> r { _stack = x }+-----------------------------------------------------------------------------+synch :: Synch p m a ()+synch = mapM_ go =<< pop+ where+ go :: ComponentState p m a -> Synch p m a ()+ go cs = do+ seen <- IS.member (cs ^. componentId) <$> use visited+ when (not seen) $ do+ propagateParent cs (cs ^. parentId)+ propagateChildren cs (cs ^. children)+ markVisited (cs ^. componentId)+ synch+-----------------------------------------------------------------------------+propagateChildren+ :: forall p m a+ . ComponentState p m a+ -> ComponentIds+ -> Synch p m a ()+propagateChildren currentState childComponents = do+ forM_ (IS.toList childComponents) $ \childId -> do+ childState <- unsafeCoerce (IM.! childId) <$> use state+ updatedChild <- unsafeCoerce <$>+ foldM process childState (childState ^. componentBindings)+ let isChildDirty =+ (_componentModelDirty childState)+ (_componentModel childState)+ (_componentModel updatedChild)+ when isChildDirty $ do+ state.at childId ?= updatedChild { _componentIsDirty = True }+ visit childId+ where+ process+ :: ComponentState m child a+ -> Binding m child+ -> Synch p m a (ComponentState m child a)+ process childState = \case+ ParentToChild getCurrentField setChildField -> do+ let currentChildModel = childState ^. componentModel+ currentFieldValue = getCurrentField (currentState ^. componentModel)+ updatedChildModel = setChildField currentFieldValue currentChildModel+ pure (childState & componentModel .~ updatedChildModel)+ Bidirectional getCurrentField _ _ setChildField -> do+ let currentChildModel = _componentModel childState+ currentFieldValue = getCurrentField (currentState ^. componentModel)+ updatedChildModel = setChildField currentFieldValue currentChildModel+ pure (childState & componentModel .~ updatedChildModel)+ _ ->+ pure childState+-----------------------------------------------------------------------------+propagateParent+ :: forall p m a+ . ComponentState p m a+ -> ComponentId+ -> Synch p m a ()+propagateParent currentState parentId_ =+ IM.lookup parentId_ <$> use state >>= mapM_ \case+ parentState -> do+ updatedParent <- unsafeCoerce <$>+ foldM process (unsafeCoerce parentState) (currentState ^. componentBindings)+ let isParentDirty =+ (_componentModelDirty parentState)+ (_componentModel parentState)+ (_componentModel updatedParent)+ when isParentDirty $ do+ state.at parentId_ ?= updatedParent { _componentIsDirty = True }+ visit parentId_+ where+ process+ :: ComponentState x p a+ -> Binding p m+ -> Synch p m a (ComponentState x p a)+ process parentState = \case+ ChildToParent setParentField getCurrentField -> do+ let currentParentModel = parentState ^. componentModel+ currentFieldValue = getCurrentField (currentState ^. componentModel)+ updatedParentModel = setParentField currentFieldValue currentParentModel+ pure (parentState & componentModel .~ updatedParentModel)+ Bidirectional _ setParentField getCurrentField _ -> do+ let currentParentModel = parentState ^. componentModel+ currentFieldValue = getCurrentField (currentState ^. componentModel)+ updatedParentModel = setParentField currentFieldValue currentParentModel+ pure (parentState & componentModel .~ updatedParentModel)+ _ ->+ pure parentState+-----------------------------------------------------------------------------+markVisited :: ComponentId -> Synch p m a ()+markVisited vcompId = visited.at vcompId ?= ()+-----------------------------------------------------------------------------+visit :: ComponentId -> Synch p m a ()+visit vcompId = stack %= (vcompId:)+-----------------------------------------------------------------------------+pop :: Synch p m a (Maybe (ComponentState p m a))+pop = use stack >>= \case+ [] -> + pure Nothing+ x : xs -> do+ stack .= xs+ use (state . at x)+-----------------------------------------------------------------------------+initialDraw+ :: Eq m+ => m+ -> Events+ -> Hydrate+ -> Bool+ -> Component p m a+ -> ComponentState p m a+ -> IO ()+initialDraw initializedModel events hydrate isRoot Component {..} ComponentState {..} = do+#ifdef BENCH+ start <- FFI.now+#endif+ vtree <- buildVTree events _componentParentId _componentId hydrate _componentSink logLevel (view initializedModel)+#ifdef BENCH+ end <- FFI.now+ when isRoot $ FFI.consoleLog $ ms (printf "buildVTree: %.3f ms" (end - start) :: String)+#endif+ case hydrate of+ Draw -> do+ Diff.diff Nothing (Just vtree) _componentDOMRef+ atomicWriteIORef _componentVTree vtree+ Hydrate -> do+ if isRoot+ then do+ hydrated <- Hydrate.hydrate logLevel _componentDOMRef vtree+ if hydrated+ then do+ atomicWriteIORef _componentVTree vtree+ else do+ newTree <-+ buildVTree events _componentParentId _componentId Draw+ _componentSink logLevel (view initializedModel)+ Diff.diff Nothing (Just newTree) _componentDOMRef+ liftIO (atomicWriteIORef _componentVTree newTree)+ else+ atomicWriteIORef _componentVTree vtree+-----------------------------------------------------------------------------+-- | Pulls the next Component for processing out of the queue, along with+-- its events.+getBatch :: IO (Maybe (ComponentId, [action]))+getBatch = do+ liftIO $ atomicModifyIORef' globalQueue $ \q ->+ case dequeue q of+ Nothing -> (q, Nothing)+ Just (vcompId, actions, newQueue) ->+ (newQueue, Just (vcompId, actions))+-----------------------------------------------------------------------------+-- | Helper for event extraction at a specific 'ComponentId'+drainQueueAt :: ComponentId -> IO [a]+drainQueueAt vcompId = liftIO $ atomicModifyIORef' globalQueue (dequeueAt vcompId)+-----------------------------------------------------------------------------+-- | Data type for holding the events in the system along with+-- the schedule of what events should be processed next+data Queue action+ = Queue+ { _queue :: IntMap (Seq action)+ , _queueSchedule :: Seq ComponentId+ } deriving (Show, Eq)+-----------------------------------------------------------------------------+emptyQueue :: Queue action+emptyQueue = mempty+-----------------------------------------------------------------------------+instance Semigroup (Queue action) where+ Queue q1 s1 <> Queue q2 s2 = Queue (q1 <> q2) (s1 <> s2)+-----------------------------------------------------------------------------+instance Monoid (Queue action) where+ mempty = Queue mempty mempty+-----------------------------------------------------------------------------+queue :: Lens (Queue action) (IntMap (Seq action))+queue = lens _queue $ \r f -> r { _queue = f }+-----------------------------------------------------------------------------+queueSchedule :: Lens (Queue action) (Seq ComponentId)+queueSchedule = lens _queueSchedule $ \r f -> r { _queueSchedule = f }+-----------------------------------------------------------------------------+enqueue :: ComponentId -> action -> Queue action -> Queue action+enqueue vcompId action q =+ q & queue %~ IM.insertWith (flip (<>)) vcompId (S.singleton action)+ & queueSchedule %~ (S.|> vcompId)+-----------------------------------------------------------------------------+-- | Case on queue schedule, get first item, span on the rest of queueSchedule, get length.+-- set schedule with whatever remains.+--+-- Take the length of the queue schedule found, looking up with vcompId (from first element)+-- in the queue, splitAt the queue.+--+dequeue+ :: forall action+ . Queue action+ -> Maybe (ComponentId, [action], Queue action)+dequeue q =+ case q ^. queueSchedule of+ S.Empty -> Nothing+ sched@(vcompId S.:<| leftover) ->+ case q ^. queue . at vcompId of+ Nothing -> -- dmj: if unmount occurred, just pop the schedule+ Just (vcompId, [], q & queueSchedule .~ leftover)+ Just actions ->+ case S.spanl (==vcompId) sched of+ (scheduled, remaining) ->+ case S.splitAt (length scheduled) actions of+ (process, rest) -> do+ let updated =+ q & queueSchedule .~ remaining+ & queue.at vcompId .~ do if null rest then Nothing else Just rest+ Just (vcompId, toList process, updated)+-----------------------------------------------------------------------------+-- | Dequeues everything from the Queue at a specific t'ComponentId', draining+-- both the queue events and the queue schedule.+dequeueAt+ :: forall action+ . ComponentId+ -> Queue action+ -> (Queue action, [action])+dequeueAt vcompId q =+ case q ^. queue . at vcompId of+ Nothing -> (q, [])+ Just actions -> do+ -- dmj: remove from schedule, extract all events+ let updated = q & queueSchedule %~ S.filter (/=vcompId)+ & queue.at vcompId .~ Nothing+ (updated, toList actions)+-----------------------------------------------------------------------------+globalWaiter :: Waiter+{-# NOINLINE globalWaiter #-}+globalWaiter = unsafePerformIO waiter+-----------------------------------------------------------------------------+globalQueue :: IORef (Queue action)+{-# NOINLINE globalQueue #-}+globalQueue = unsafePerformIO (newIORef emptyQueue)+-----------------------------------------------------------------------------+componentId :: Lens (ComponentState parent model action) ComponentId+componentId = lens _componentId $ \record field -> record { _componentId = field }+-----------------------------------------------------------------------------+parentId :: Lens (ComponentState parent model action) ComponentId+parentId = lens _componentParentId $ \record field -> record { _componentParentId = field }+-----------------------------------------------------------------------------+children :: Lens (ComponentState parent model action) (ComponentIds)+children = lens _componentChildren $ \record field -> record { _componentChildren = field }+-----------------------------------------------------------------------------+componentTopics :: Lens (ComponentState parent model action) (Map MisoString (Value -> IO ()))+componentTopics = lens _componentTopics $ \record field -> record { _componentTopics = field }+-----------------------------------------------------------------------------+isDirty :: Lens (ComponentState parent model action) Bool+isDirty = lens _componentIsDirty $ \record field -> record { _componentIsDirty = field }+-----------------------------------------------------------------------------+componentModel :: Lens (ComponentState parent model action) model+componentModel = lens _componentModel $ \record field -> record { _componentModel = field }+-----------------------------------------------------------------------------+componentBindings :: Lens (ComponentState p m a) [Binding p m]+componentBindings = lens _componentBindings $ \record field -> record { _componentBindings = field }+-----------------------------------------------------------------------------+-- | Hydrate avoids calling @diff@, and instead calls @hydrate@+-- 'Draw' invokes 'Miso.Diff.diff'+data Hydrate+ = Draw+ | Hydrate+ deriving (Show, Eq)+-----------------------------------------------------------------------------+-- | t'Miso.Types.Component' state, data associated with the lifetime of a t'Miso.Types.Component'+data ComponentState parent model action+ = ComponentState+ { _componentId :: ComponentId+ -- ^ The ID of the current t'Miso.Types.Component'+ , _componentParentId :: ComponentId+ -- ^ The ID of the t'Miso.Types.Component''s parent+ , _componentSubThreads :: IORef (Map MisoString ThreadId)+ -- ^ Mapping of all 'Sub' in use by t'Miso.Types.Component'+ , _componentDOMRef :: DOMRef+ -- ^ The DOM reference the t'Miso.Types.Component' is mounted on+ , _componentVTree :: IORef VTree+ -- ^ A reference to the current virtual DOM (i.e. t'VTree')+ , _componentSink :: action -> IO ()+ -- ^ t'Miso.Types.Component' t'Sink' used to enter events into the system+ , _componentModel :: model+ -- ^ t'Miso.Types.Component' state+ , _componentIsDirty :: Bool+ -- ^ Indicator if t'Miso.Types.Component' needs to be drawn+ , _componentScripts :: [DOMRef]+ -- ^ DOM references for \<script\> and \<style\> appended to \<head\>+ , _componentEvents :: Events+ -- ^ List of events a t'Miso.Types.Component' listens on+ , _componentBindings :: [Binding parent model]+ -- ^ Declarative bindings between t'Miso.Types.Component' 'model'.+ , _componentMailbox :: Value -> Maybe action+ -- ^ Mailbox for asynchronous t'Miso.Types.Component' communication+ , _componentDraw :: model -> IO ()+ -- ^ Helper function for t'Miso.Types.Component' rendering+ , _componentModelDirty :: model -> model -> Bool+ -- ^ Model diffing+ , _componentApplyActions+ :: [action]+ -> model+ -> IntMap (ComponentState parent model action)+ -> (IntMap (ComponentState parent model action), model, [Schedule action], ComponentIds)+ -- ^ t'Miso.Types.Component' actions application+ , _componentTopics :: Map MisoString (Value -> IO ())+ -- ^ t'Miso.Types.Component' topics using for Pub Sub async communication.+ , _componentChildren :: ComponentIds+ }+-----------------------------------------------------------------------------+-- | A @Topic@ represents a place to send and receive messages. @Topic@ is used to facilitate+-- communication between t'Miso.Types.Component'. t'Miso.Types.Component' can 'subscribe' to or 'publish' to any @Topic@,+-- within the same t'Miso.Types.Component' or across t'Miso.Types.Component'.+--+-- This requires creating a custom 'ToJSON' / 'FromJSON'. Any other t'Miso.Types.Component'+-- can 'publish' or 'subscribe' to this @Topic message@. It is a way to provide+-- loosely-coupled communication between @Components@.+--+-- See 'publish', 'subscribe', 'unsubscribe' for more details.+--+-- When distributing t'Miso.Types.Component' for third-party use, it is recommended to export+-- the @Topic@, where message is the JSON protocol.+--+--+-- @since 1.9.0.0+newtype Topic a = Topic MisoString+ deriving (Ord, Eq, Show, ToMisoString)+-----------------------------------------------------------------------------+-- | Smart constructor for creating a @Topic message@ to write to+--+-- @+--+-- data Message+-- = Increment+-- | Decrement+-- deriving (Show, Eq, Generic, ToJSON, FromJSON)+--+-- arithmetic :: Topic Message+-- arithmetic = topic "arithmetic"+--+-- data Action+-- = Notification (Result Message)+-- | Subscribe+-- | Unsubscribe+--+-- update_ :: Action -> Effect Int Action+-- update_ = \case+-- Unsubscribe ->+-- unsubscribe arithmetic+-- Subscribe ->+-- subscribe arithmetic Notification+-- Notification (Success Increment) ->+-- update_ AddOne+-- Notification (Success Decrement) ->+-- update_ SubtractOne+-- Notification (Error msg) ->+-- io_ $ consoleError ("Decode failure: " <> ms msg)+--+-- @+--+-- @since 1.9.0.0+topic :: MisoString -> Topic a+topic = Topic+-----------------------------------------------------------------------------+-- | Subscribes to a @Topic@, provides callback function that writes to t'Miso.Types.Component' 'Sink'+--+-- If a @Topic message@ does not exist when calling 'subscribe' it is generated dynamically.+-- Each subscriber decodes the received 'Value' using it's own 'FromJSON' instance. This provides+-- for loose-coupling between t'Miso.Types.Component'. As long as the underlying 'Value' are identical+-- t'Miso.Types.Component' can use their own types without serialization issues. @Topic message@ should+-- have their own JSON API specification when being distributed.+--+-- @+--+-- arithmetic :: Topic Message+-- arithmetic = topic "arithmetic"+--+-- clientComponent :: MisoString -> Component Int Action+-- clientComponent name = component 0 update_ $ \m ->+-- div_+-- []+-- [ br_ []+-- , text (name <> " : " <> ms (m ^. _id))+-- , button_ [ onClick Unsubscribe ] [ "unsubscribe" ]+-- , button_ [ onClick Subscribe ] [ "subscribe" ]+-- ] where+-- update_ :: Action -> Effect Int Action+-- update_ = \case+-- AddOne -> do+-- _id += 1+-- SubtractOne ->+-- _id -= 1+-- Unsubscribe ->+-- unsubscribe arithmetic+-- Subscribe ->+-- subscribe arithmetic Notification+-- Notification (Success Increment) -> do+-- update_ AddOne+-- Notification (Success Decrement) -> do+-- update_ SubtractOne+-- Notification (Error msg) ->+-- io_ $ consoleError ("Decode failure: " <> ms msg)+-- _ -> pure ()+--+-- @+--+-- @since 1.9.0.0+subscribe+ :: FromJSON message+ => Topic message+ -> (message -> action)+ -> (MisoString -> action)+ -> Effect parent model action+subscribe (Topic topicName) successful errorful = do+ ComponentInfo {..} <- ask+ withSink $ \sink ->+ modifyComponent _componentInfoId $ do+ componentTopics %= do+ M.insert topicName $ \value ->+ sink (case fromJSON value of+ Success s -> successful s+ Error e -> errorful e)+-----------------------------------------------------------------------------+-- Pub / Sub implementation+--+-- (Subscribe)+--+-- Check if you're already subscribed to this topic.+--+-- [true] - If you're already subscribed, then it's a no-op (warn)+--+-- [false] - If you're not subscribed then fork a new thread that holds the duplicated topic+-- and blocks on the read end of the duplicated topic, sink messages into component sink+--+-- (Unsubscribe)+--+-- Check if you're already subscribed to this topic+--+-- [true] - Kill the thread, delete the subscriber entry+--+-- [false] - If you're not subscribed, then it's a no-op (warn)+--+-- (Publish)+--+-- Check if the Topic exists+--+-- [true] - If it exists then write the message to the topic+--+-- [false] - If it doesn't exist, create it.+--+-- N.B. Components can be both publishers and subscribers to their own topics.+-----------------------------------------------------------------------------+-- | Unsubscribe from a t'Topic'+--+-- Unsubscribes a t'Miso.Types.Component' from receiving messages from t'Topic'+--+-- See 'subscribe' for more use.+--+-- @since 1.9.0.0+unsubscribe :: Topic message -> Effect parent model action+unsubscribe (Topic topicName) = do+ ComponentInfo {..} <- ask+ io_ $ modifyComponent _componentInfoId $ do+ (componentTopics %= M.delete topicName)+-----------------------------------------------------------------------------+-- | Publish to a t'Topic message'+--+-- t'Topic message' are generated dynamically if they do not exist. When using 'publish'+-- all subscribers are immediately notified of a new message. A message is distributed as a 'Value'+-- The underlying 'ToJSON' instance is used to construct this 'Value'.+--+-- We recommend documenting a public API for the JSON protocol message when distributing a t'Miso.Types.Component'+-- downstream to end users for consumption (be it inside a single cabal project or across multiple+-- cabal projects).+--+-- @+--+-- arithmetic :: Topic Message+-- arithmetic = topic "arithmetic"+--+-- server :: Component () Action+-- server = component () update_ $ \() ->+-- div_+-- []+-- [ "Server component"+-- , button_ [ onClick AddOne ] [ "+" ]+-- , button_ [ onClick SubtractOne ] [ "-" ]+-- , component_ (client_ "client 1")+-- [ onMountedWith Mount+-- ]+-- , component_ (client_ "client 2")+-- [ onMountedWith Mount+-- ]+-- ] where+-- update_ :: Action -> Effect parent () Action+-- update_ = \case+-- AddOne ->+-- publish arithmetic Increment+-- SubtractOne ->+-- publish arithemtic Decrement+--+-- @+--+-- @since 1.9.0.0+publish+ :: ToJSON message+ => Topic message+ -> message+ -> IO ()+publish (Topic topicName) message = mapM_ go =<< IM.elems <$> readIORef components+ where+ go ComponentState {..} = do+ case M.lookup topicName _componentTopics of+ Nothing ->+ pure ()+ Just f -> do+ liftIO (f (toJSON message))+-----------------------------------------------------------------------------+subIds :: IORef Int+{-# NOINLINE subIds #-}+subIds = unsafePerformIO $ newIORef 0+-----------------------------------------------------------------------------+freshSubId :: IO MisoString+freshSubId = do+ x <- atomicModifyIORef' subIds $ \y -> (y + 1, y)+ pure ("miso-sub-id-" <> ms x)+-----------------------------------------------------------------------------+-- | This is used to demarcate the ROOT of a page. This ID will *never*+-- exist in the `components` map.+rootComponentId :: ComponentId+rootComponentId = 0+-----------------------------------------------------------------------------+-- | This is the top-level ComponentId, hardcoded+topLevelComponentId :: ComponentId+topLevelComponentId = 1+-----------------------------------------------------------------------------+-- | The global store of 'ComponentId', for internal-use only.+--+-- Used internally @freshComponentId@ to allocate new 'ComponentId' on+-- mount.+--+componentIds :: IORef Int+{-# NOINLINE componentIds #-}+componentIds = unsafePerformIO $ newIORef topLevelComponentId+-----------------------------------------------------------------------------+freshComponentId :: IO ComponentId+freshComponentId = atomicModifyIORef' componentIds $ \y -> (y + 1, y)+-----------------------------------------------------------------------------+-- | componentMap+--+-- This is a global t'Miso.Types.Component' @Map@ that holds the state of all currently+-- mounted t'Miso.Types.Component's+components :: IORef (IntMap (ComponentState parent model action))+{-# NOINLINE components #-}+components = unsafePerformIO (newIORef mempty)+-----------------------------------------------------------------------------+-- | This function evaluates effects according to 'Synchronicity'.+evalScheduled :: Synchronicity -> IO () -> IO ()+evalScheduled Sync x = x `catch` (void . exception)+evalScheduled Async x = void (forkIO (x `catch` (void . exception)))+-----------------------------------------------------------------------------+exception :: SomeException -> IO ()+exception ex = FFI.consoleError ("[EXCEPTION]: " <> ms ex)+-----------------------------------------------------------------------------+-- | Drains the event queue before unmounting, executed synchronously.+drain+ :: ComponentState parent model action+ -> IO ()+drain ComponentState {..} = do+ drainQueueAt _componentId >>= \case+ [] -> pure ()+ actions -> do+ vcomps <- readIORef components+ case _componentApplyActions actions _componentModel vcomps of+ (newVComps, _, schedules, _) -> do+ forM_ schedules $ \case+ -- dmj: process all actions synchronously during unmount+ Schedule _ action ->+ action _componentSink+ `catch` (\(e :: SomeException) -> void (evaluate e))+ -- dmj: Don't recurse on drain, we only fire-off the last set+ -- of events for 'onBeforeUnmounted' hooks. The queue will+ -- ignore the rest of these.+ atomicWriteIORef components newVComps+-----------------------------------------------------------------------------+-- | Post unmount call to drop the <style> and <script> in <head>+unloadScripts :: ComponentState parent model action -> IO ()+unloadScripts ComponentState {..} = do+ head_ <- FFI.getHead+ forM_ _componentScripts (FFI.removeChild head_)+-----------------------------------------------------------------------------+-- | Helper to drop all lifecycle and mounting hooks if defined.+freeLifecycleHooks :: ComponentState parent model action -> IO ()+freeLifecycleHooks ComponentState {..} = do+ VTree (Object comp) <- liftIO (readIORef _componentVTree)+ mapM_ freeFunction =<< fromJSVal =<< comp ! ("mount" :: MisoString)+ mapM_ freeFunction =<< fromJSVal =<< comp ! ("unmount" :: MisoString)+-----------------------------------------------------------------------------+-- | Helper function for cleanly destroying a t'Miso.Types.Component'+unmountComponent+ :: ComponentState parent model action+ -> IO ()+unmountComponent cs@ComponentState {..} = do+ liftIO (mapM_ killThread =<< readIORef _componentSubThreads)+ drain cs+ finalizeWebSockets _componentId+ finalizeEventSources _componentId+ unloadScripts cs+ freeLifecycleHooks cs+ liftIO $ modifyComponent _componentParentId $ do+ children.at _componentId .= Nothing+ liftIO $ atomicModifyIORef' components $ \m -> (IM.delete _componentId m, ())+ FFI.unmountComponent _componentId+-----------------------------------------------------------------------------+resetComponentState :: IO () -> IO ()+resetComponentState clear = do+ cs <- atomicModifyIORef' components $ \vcomps -> (mempty, vcomps)+ atomicWriteIORef globalQueue mempty+ atomicWriteIORef componentIds topLevelComponentId+ atomicWriteIORef subIds 0+ forM_ cs unmountComponent+ clear+-----------------------------------------------------------------------------+-- | Internal function for construction of a Virtual DOM.+--+-- Component mounting should be synchronous.+-- Mounting causes a recursive diffing to occur+-- (creating sub components as detected), setting up+-- infrastructure for each sub-component. During this+-- process we go between the Haskell heap and the JS heap.+buildVTree+ :: Eq model+ => Events+ -> ComponentId+ -> ComponentId+ -> Hydrate+ -> Sink action+ -> LogLevel+ -> View model action+ -> IO VTree+buildVTree events_ parentId_ vcompId hydrate snk logLevel_ = \case+ VComp maybeKey (SomeComponent app) -> do+ vcomp_ <- create++ mountCallback <- do+ syncCallback1' $ \parent_ -> do+ ComponentState {..} <- initialize events_ vcompId hydrate False app (pure parent_)+ modifyComponent vcompId (children %= IS.insert _componentId)+ vtree <- toJSVal =<< readIORef _componentVTree+ FFI.set "parent" vcomp_ (Object vtree)+ obj <- create+ setProp "componentId" _componentId obj+ setProp "componentTree" vtree obj+ toJSVal obj++ unmountCallback <- toJSVal =<< do+ FFI.syncCallback1 $ \vcompId_ -> do+ componentId_ <- fromJSValUnchecked vcompId_+ IM.lookup componentId_ <$> readIORef components >>= \case+ Nothing -> pure ()+ Just componentState -> do+ forM_ (unmount app) (_componentSink componentState)+ unmountComponent componentState++ FFI.set "child" jsNull vcomp_+ forM_ maybeKey (\key -> FFI.set "key" key vcomp_)+ FFI.set "mount" mountCallback vcomp_+ FFI.set "unmount" unmountCallback vcomp_+ FFI.set "eventPropagation" (eventPropagation app) vcomp_+ FFI.set "type" VCompType vcomp_+ pure (VTree vcomp_)+ VNode ns tag attrs kids -> do+ vnode_ <- createNode "vnode" ns tag+ setAttrs vnode_ attrs snk logLevel_ events_+ vchildren <- toJSVal =<< procreate vnode_+ flip (FFI.set "children") vnode_ vchildren+ flip (FFI.set "type") vnode_ =<< toJSVal VNodeType+ pure (VTree vnode_)+ where+ procreate parentVTree = do+ kidsViews <- forM kids $ \kid -> do+ VTree child <- buildVTree events_ parentId_ vcompId hydrate snk logLevel_ kid+ FFI.set "parent" parentVTree child+ pure child+ setNextSibling kidsViews+ pure kidsViews+ where+ setNextSibling xs =+ zipWithM_ (flip setField "nextSibling")+ xs (drop 1 xs)+ VText key t -> do+ vtree <- create+ flip (FFI.set "type") vtree =<< toJSVal VTextType+ forM_ key $ \k -> FFI.set "key" (ms k) vtree+ FFI.set "ns" ("text" :: MisoString) vtree+ FFI.set "text" t vtree+ pure (VTree vtree)+-----------------------------------------------------------------------------+-- | @createNode@+-- A helper function for constructing a vtree (used for @vcomp@ and @vnode@)+-- Doesn't handle children+createNode :: MisoString -> Namespace -> MisoString -> IO Object+createNode typ ns tag = do+ vnode_ <- create+ cssObj <- create+ propsObj <- create+ eventsObj <- create+ captures <- create+ bubbles <- create+ FFI.set "css" cssObj vnode_+ FFI.set "type" typ vnode_+ FFI.set "props" propsObj vnode_+ FFI.set "events" eventsObj vnode_+ FFI.set "captures" captures eventsObj+ FFI.set "bubbles" bubbles eventsObj+ FFI.set "ns" ns vnode_+ FFI.set "tag" tag vnode_+ pure vnode_+-----------------------------------------------------------------------------+-- | Helper function for populating "props" and "css" fields on a virtual+-- DOM node+setAttrs+ :: Object+ -> [Attribute action]+ -> Sink action+ -> LogLevel+ -> Events+ -> IO ()+setAttrs vnode_@(Object jval) attrs snk logLevel events =+ forM_ attrs $ \case+ Property "key" v -> do+ value <- toJSVal v+ FFI.set "key" value vnode_+ ClassList classes ->+ FFI.populateClass jval classes+ Property k v -> do+ value <- toJSVal v+ o <- getProp "props" vnode_+ FFI.set k value (Object o)+ On callback ->+ callback snk (VTree vnode_) logLevel events+ Styles styles -> do+ cssObj <- getProp "css" vnode_+ forM_ (M.toList styles) $ \(k,v) -> do+ FFI.set k v (Object cssObj)+-----------------------------------------------------------------------------+-- | Registers components in the global state+registerComponent :: MonadIO m => ComponentState parent model action -> m ()+registerComponent componentState = liftIO $+ atomicModifyIORef' components $ \cs ->+ (IM.insert (_componentId componentState) componentState cs, ())+-----------------------------------------------------------------------------+-- | Renders styles+--+-- Meant for development purposes+-- Appends CSS to <head>+--+renderStyles :: [CSS] -> IO [DOMRef]+renderStyles styles =+ forM styles $ \case+ Href url cacheBust -> FFI.addStyleSheet url cacheBust+ Style css -> FFI.addStyle css+ Sheet sheet -> FFI.addStyle (renderStyleSheet sheet)+-----------------------------------------------------------------------------+-- | Renders scripts+--+-- Meant for development purposes+-- Appends JS to <head>+--+renderScripts :: [JS] -> IO [DOMRef]+renderScripts scripts =+ forM scripts $ \case+ Src src cacheBust ->+ FFI.addSrc src cacheBust+ Script script ->+ FFI.addScript False script+ Module src ->+ FFI.addScript True src+ ImportMap importMap -> do+ o <- create+ imports <- create+ forM_ importMap $ \(k,v) ->+ FFI.set k v imports+ FFI.set "imports" imports o+ FFI.addScriptImportMap+ =<< jsonStringify+ =<< toJSVal o+-----------------------------------------------------------------------------+-- | Starts a named 'Sub' dynamically, during the life of a t'Miso.Types.Component'.+-- The 'Sub' can be stopped by calling @Ord subKey => stop subKey@ from the 'update' function.+-- All 'Sub' started will be stopped if a t'Miso.Types.Component' is unmounted.+--+-- @+-- data SubType = LoggerSub | TimerSub+-- deriving (Eq, Ord)+--+-- update Action =+-- startSub LoggerSub $ \\sink -> forever (threadDelay (secs 1) >> consoleLog "test")+-- @+--+-- @since 1.9.0.0+startSub+ :: ToMisoString subKey+ => subKey+ -- ^ The key used to track the 'Sub'+ -> Sub action+ -- ^ The 'Sub'+ -> Effect parent model action+startSub subKey sub = do+ ComponentInfo {..} <- ask+ io_ $ do+ IM.lookup _componentInfoId <$> liftIO (readIORef components) >>= \case+ Nothing -> pure ()+ Just compState@ComponentState {..} -> do+ mtid <- liftIO (M.lookup (ms subKey) <$> readIORef _componentSubThreads)+ case mtid of+ Nothing ->+ startThread compState+ Just tid -> do+ status <- threadStatus tid+ case status of+ ThreadFinished -> startThread compState+ ThreadDied -> startThread compState+ _ -> pure ()+ where+ startThread ComponentState {..} = do+ tid <- forkIO (sub _componentSink)+ atomicModifyIORef' _componentSubThreads $ \m ->+ (M.insert (ms subKey) tid m, ())+-----------------------------------------------------------------------------+-- | Stops a named 'Sub' dynamically, during the life of a t'Miso.Types.Component'.+-- All 'Sub' started will be stopped automatically if a t'Miso.Types.Component' is unmounted.+--+-- @+-- data SubType = LoggerSub | TimerSub+-- deriving (Eq, Ord)+--+-- update Action = do+-- stopSub LoggerSub+-- @+--+-- @since 1.9.0.0+stopSub+ :: ToMisoString subKey+ => subKey+ -- ^ The key used to stop the 'Sub'+ -> Effect parent model action+stopSub subKey = do+ vcompId <- asks _componentInfoId+ io_ $ do+ IM.lookup vcompId <$> readIORef components >>= \case+ Nothing -> do+ pure ()+ Just ComponentState {..} -> do+ mtid <- liftIO (M.lookup (ms subKey) <$> readIORef _componentSubThreads)+ forM_ mtid $ \tid ->+ liftIO $ do+ atomicModifyIORef' _componentSubThreads $ \m -> (M.delete (ms subKey) m, ())+ killThread tid+-----------------------------------------------------------------------------+-- | Send any @ToJSON message => message@ to a t'Miso.Types.Component' mailbox, by 'ComponentId'+--+-- @+-- io_ $ mail componentId ("test message" :: MisoString) :: Effect parent model action+-- @+--+-- @since 1.9.0.0+mail+ :: ToJSON message+ => ComponentId+ -- ^ 'ComponentId' to receive 'mail'+ -> message+ -- ^ The message to send+ -> IO ()+mail vcompId msg =+ IM.lookup vcompId <$> readIORef components >>= \case+ Nothing -> pure ()+ Just ComponentState{..} ->+ case _componentMailbox (toJSON msg) of+ Nothing -> pure ()+ Just action ->+ _componentSink action+-----------------------------------------------------------------------------+-- | Send any @ToJSON message => message@ to the parent's t'Miso.Types.Component' mailbox+--+-- @+-- mailParent ("test message" :: MisoString) :: Effect parent model action+-- @+--+-- @since 1.9.0.0+mailParent+ :: ToJSON message+ => message+ -- ^ Message to send+ -> Effect parent model action+mailParent msg = do+ ComponentInfo {..} <- ask+ io_ (mail _componentInfoParentId msg)+----------------------------------------------------------------------------+-- | Helper function for processing @Mail@ from 'mail'.+--+-- @+--+-- data Action+-- = ParsedMail Message+-- | ErrorMail MisoString+--+-- main :: IO ()+-- main = app { mailbox = checkMail ParsedMail ErrorMail }+-- @+--+-- @since 1.9.0.0+checkMail+ :: FromJSON value+ => (value -> action)+ -- ^ Successful callback+ -> (MisoString -> action)+ -- ^ Errorful callback+ -> Value+ -- ^ The message received to parse.+ -> Maybe action+checkMail successful errorful value =+ pure $ case fromJSON value of+ Success x -> successful x+ Error err -> errorful (ms err)+-----------------------------------------------------------------------------+-- | Fetches the parent `model` from the child (if @parent@ exists).+--+-- N.B. this is a no-op for 'ROOT'.+--+-- @since 1.9.0.0+parent+ :: (parent -> action)+ -- ^ Successful callback+ -> action+ -- ^ Errorful callback+ -> Effect parent model action+parent successful errorful = do+ ComponentInfo {..} <- ask+ withSink $ \sink -> do+ IM.lookup _componentInfoParentId <$> liftIO (readIORef components) >>= \case+ Nothing -> sink errorful+ Just ComponentState {..} -> do+ sink (successful _componentModel)+-----------------------------------------------------------------------------+-- | Sends a message to all t'Miso.Types.Component' 'mailbox', excluding oneself.+--+-- @+--+-- update :: action -> Effect parent model action+-- update _ = broadcast (String "public service announcement")+-- @+--+-- @since 1.9.0.0+broadcast+ :: Eq model+ => ToJSON message+ => message+ -- ^ Message to broadcast to all other 'Component'+ -> Effect parent model action+broadcast msg = do+ ComponentInfo {..} <- ask+ io_ $ do+ vcompIds <- IM.keys <$> readIORef components+ forM_ vcompIds $ \vcompId ->+ when (_componentInfoId /= vcompId) $ do+ IM.lookup vcompId <$> readIORef components >>= \case+ Nothing -> pure ()+ Just ComponentState{..} ->+ case _componentMailbox (toJSON msg) of+ Nothing -> pure ()+ Just action -> _componentSink action+-----------------------------------------------------------------------------+type Socket = JSVal+-----------------------------------------------------------------------------+type WebSockets = IM.IntMap (IM.IntMap Socket)+-----------------------------------------------------------------------------+type EventSources = IM.IntMap (IM.IntMap Socket)+-----------------------------------------------------------------------------+websocketConnections :: IORef WebSockets+{-# NOINLINE websocketConnections #-}+websocketConnections = unsafePerformIO (newIORef IM.empty)+-----------------------------------------------------------------------------+websocketConnectionIds :: IORef Int+{-# NOINLINE websocketConnectionIds #-}+websocketConnectionIds = unsafePerformIO (newIORef (0 :: Int))+-----------------------------------------------------------------------------+websocketConnectText+ :: URL+ -- ^ t'WebSocket' 'URL'+ -> (WebSocket -> action)+ -- ^ onOpen+ -> (Closed -> action)+ -- ^ onClosed+ -> (MisoString -> action)+ -- ^ onMessage+ -> (MisoString -> action)+ -- ^ onError+ -> Effect parent model action+websocketConnectText url onOpen onClosed onMessage onError =+ websocketCore $ \webSocketId sink ->+ FFI.websocketConnect url+ (sink $ onOpen webSocketId)+ (sink . onClosed <=< fromJSValUnchecked)+ (pure (sink . onMessage <=< fromJSValUnchecked))+ Nothing+ Nothing+ Nothing+ (sink . onError <=< fromJSValUnchecked)+ True+-----------------------------------------------------------------------------+websocketConnectBLOB+ :: URL+ -- ^ t'WebSocket' 'URL'+ -> (WebSocket -> action)+ -- ^ onOpen+ -> (Closed -> action)+ -- ^ onClosed+ -> (Blob -> action)+ -- ^ onMessage+ -> (MisoString -> action)+ -- ^ onError+ -> Effect parent model action+websocketConnectBLOB url onOpen onClosed onMessage onError =+ websocketCore $ \webSocketId sink ->+ FFI.websocketConnect url+ (sink $ onOpen webSocketId)+ (sink . onClosed <=< fromJSValUnchecked)+ Nothing+ Nothing+ (pure (sink . onMessage . Blob))+ Nothing+ (sink . onError <=< fromJSValUnchecked)+ False+-----------------------------------------------------------------------------+websocketConnectArrayBuffer+ :: URL+ -- ^ t'WebSocket' 'URL'+ -> (WebSocket -> action)+ -- ^ onOpen+ -> (Closed -> action)+ -- ^ onClosed+ -> (ArrayBuffer -> action)+ -- ^ onMessage+ -> (MisoString -> action)+ -- ^ onError+ -> Effect parent model action+websocketConnectArrayBuffer url onOpen onClosed onMessage onError =+ websocketCore $ \webSocketId sink ->+ FFI.websocketConnect url+ (sink $ onOpen webSocketId)+ (sink . onClosed <=< fromJSValUnchecked)+ Nothing+ Nothing+ Nothing+ (pure (sink . onMessage . ArrayBuffer))+ (sink . onError <=< fromJSValUnchecked)+ False+-----------------------------------------------------------------------------+websocketConnectJSON+ :: FromJSON json+ => URL+ -- ^ WebSocket URL+ -> (WebSocket -> action)+ -- ^ onOpen+ -> (Closed -> action)+ -- ^ onClosed+ -> (json -> action)+ -- ^ onMessage+ -> (MisoString -> action)+ -- ^ onError+ -> Effect parent model action+websocketConnectJSON url onOpen onClosed onMessage onError =+ websocketCore $ \webSocketId sink ->+ FFI.websocketConnect url+ (sink $ onOpen webSocketId)+ (sink . onClosed <=< fromJSValUnchecked)+ Nothing+ (pure (\bytes -> do+ value :: Value <- fromJSValUnchecked bytes+ case fromJSON value of+ Error msg -> sink $ onError (ms msg)+ Success x -> sink $ onMessage x))+ Nothing+ Nothing+ (sink . onError <=< fromJSValUnchecked)+ False+-----------------------------------------------------------------------------+websocketConnect+ :: FromJSON json+ => URL+ -- ^ WebSocket URL+ -> (WebSocket -> action)+ -- ^ onOpen+ -> (Closed -> action)+ -- ^ onClosed+ -> (Payload json -> action)+ -- ^ onMessage+ -> (MisoString -> action)+ -- ^ onError+ -> Effect parent model action+websocketConnect url onOpen onClosed onMessage onError =+ websocketCore $ \webSocketId sink ->+ FFI.websocketConnect url+ (sink $ onOpen webSocketId)+ (sink . onClosed <=< fromJSValUnchecked)+ (pure (sink . onMessage . TEXT <=< fromJSValUnchecked))+ (pure (\bytes -> do+ value :: Value <- fromJSValUnchecked bytes+ case fromJSON value of+ Error msg -> sink $ onError (ms msg)+ Success x -> sink $ onMessage (JSON x)))+ (pure (sink . onMessage . BLOB . Blob))+ (pure (sink . onMessage . BUFFER . ArrayBuffer))+ (sink . onError <=< fromJSValUnchecked)+ False+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket>+websocketCore+ :: (WebSocket -> Sink action -> IO Socket)+ -> Effect parent model action+websocketCore core = do+ ComponentInfo {..} <- ask+ withSink $ \sink -> do+ webSocketId <- freshWebSocket+ socket <- core webSocketId sink+ insertWebSocket _componentInfoId webSocketId socket+ where+ insertWebSocket :: ComponentId -> WebSocket -> Socket -> IO ()+ insertWebSocket componentId_ (WebSocket socketId) socket =+ atomicModifyIORef' websocketConnections $ \websockets ->+ (update websockets, ())+ where+ update websockets =+ IM.unionWith IM.union websockets+ $ IM.singleton componentId_+ $ IM.singleton socketId socket++ freshWebSocket :: IO WebSocket+ freshWebSocket = WebSocket <$>+ atomicModifyIORef' websocketConnectionIds (\x -> (x + 1, x))+-----------------------------------------------------------------------------+getWebSocket :: ComponentId -> WebSocket -> WebSockets -> Maybe Socket+getWebSocket vcompId (WebSocket websocketId) =+ IM.lookup websocketId <=< IM.lookup vcompId+-----------------------------------------------------------------------------+finalizeWebSockets :: ComponentId -> IO ()+finalizeWebSockets vcompId = do+ mapM_ (mapM_ FFI.websocketClose . IM.elems) =<<+ IM.lookup vcompId <$> readIORef websocketConnections+ dropComponentWebSockets+ where+ dropComponentWebSockets :: IO ()+ dropComponentWebSockets =+ atomicModifyIORef' websocketConnections $ \websockets ->+ (IM.delete vcompId websockets, ())+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close>+websocketClose :: WebSocket -> Effect parent model action+websocketClose socketId = do+ ComponentInfo {..} <- ask+ io_ $ do+ result <- + atomicModifyIORef' websocketConnections $ \imap ->+ dropWebSocket _componentInfoId socketId imap =:+ getWebSocket _componentInfoId socketId imap+ case result of+ Nothing ->+ pure ()+ Just socket ->+ FFI.websocketClose socket+ where+ dropWebSocket :: ComponentId -> WebSocket -> WebSockets -> WebSockets+ dropWebSocket vcompId (WebSocket websocketId) websockets = do+ case IM.lookup vcompId websockets of+ Nothing ->+ websockets+ Just componentSockets ->+ IM.insert vcompId (IM.delete websocketId componentSockets) websockets+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send>+websocketSend+ :: ToJSON value+ => WebSocket+ -> Payload value+ -> Effect parent model action+websocketSend socketId msg = do+ ComponentInfo {..} <- ask+ io_ $ do+ getWebSocket _componentInfoId socketId <$> readIORef websocketConnections >>= \case+ Nothing -> pure ()+ Just socket ->+ case msg of+ JSON json_ ->+ FFI.websocketSend socket =<< toJSVal (encode json_)+ BUFFER arrayBuffer_ -> do+ FFI.websocketSend socket =<< toJSVal arrayBuffer_+ TEXT txt ->+ FFI.websocketSend socket =<< toJSVal txt+ BLOB blob_ ->+ FFI.websocketSend socket =<< toJSVal blob_+-----------------------------------------------------------------------------+-- | Retrieves current status of t'WebSocket'+--+-- If the t'WebSocket' identifier does not exist a 'CLOSED' is returned.+--+socketState :: WebSocket -> (SocketState -> action) -> Effect parent model action+socketState socketId callback = do+ ComponentInfo {..} <- ask+ withSink $ \sink -> do+ getWebSocket _componentInfoId socketId <$> readIORef websocketConnections >>= \case+ Just socket -> do+ x <- socket ! ("socketState" :: MisoString)+ socketstate <- toEnum <$> fromJSValUnchecked x+ sink (callback socketstate)+ Nothing ->+ sink (callback CLOSED)+-----------------------------------------------------------------------------+codeToCloseCode :: Int -> CloseCode+codeToCloseCode = \case+ 1000 -> CLOSE_NORMAL+ 1001 -> CLOSE_GOING_AWAY+ 1002 -> CLOSE_PROTOCOL_ERROR+ 1003 -> CLOSE_UNSUPPORTED+ 1005 -> CLOSE_NO_STATUS+ 1006 -> CLOSE_ABNORMAL+ 1007 -> Unsupported_Data+ 1008 -> Policy_Violation+ 1009 -> CLOSE_TOO_LARGE+ 1010 -> Missing_Extension+ 1011 -> Internal_Error+ 1012 -> Service_Restart+ 1013 -> Try_Again_Later+ 1015 -> TLS_Handshake+ n -> OtherCode n+-----------------------------------------------------------------------------+-- | Closed message is sent when a t'WebSocket' has closed+data Closed+ = Closed+ { closedCode :: CloseCode+ -- ^ The code used to indicate why a socket closed+ , wasClean :: Bool+ -- ^ If the connection was closed cleanly, or forcefully.+ , reason :: MisoString+ -- ^ The reason for socket closure.+ } deriving (Eq, Show)+-----------------------------------------------------------------------------+instance FromJSVal Closed where+ fromJSVal o = do+ closed_ <- fmap codeToCloseCode <$> do fromJSVal =<< o ! ("code" :: MisoString)+ wasClean_ <- fromJSVal =<< o ! ("wasClean" :: MisoString)+ reason_ <- fromJSVal =<< o ! ("reason" :: MisoString)+ pure (Closed <$> closed_ <*> wasClean_ <*> reason_)+-----------------------------------------------------------------------------+-- | URL that the t'WebSocket' will @connect@ to+type URL = MisoString+-----------------------------------------------------------------------------+-- | 'SocketState' corresponding to current t'WebSocket' connection+data SocketState+ = CONNECTING -- ^ 0+ | OPEN -- ^ 1+ | CLOSING -- ^ 2+ | CLOSED -- ^ 3+ deriving (Show, Eq, Ord, Enum)+-----------------------------------------------------------------------------+-- | Code corresponding to a closed connection+-- https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent+data CloseCode+ = CLOSE_NORMAL+ -- ^ 1000, Normal closure; the connection successfully completed whatever purpose for which it was created.+ | CLOSE_GOING_AWAY+ -- ^ 1001, The endpoint is going away, either because of a server failure or because the browser is navigating away from the page that opened the connection.+ | CLOSE_PROTOCOL_ERROR+ -- ^ 1002, The endpoint is terminating the connection due to a protocol error.+ | CLOSE_UNSUPPORTED+ -- ^ 1003, The connection is being terminated because the endpoint received data of a type it cannot accept (for example, a textonly endpoint received binary data).+ | CLOSE_NO_STATUS+ -- ^ 1005, Reserved. Indicates that no status code was provided even though one was expected.+ | CLOSE_ABNORMAL+ -- ^ 1006, Reserved. Used to indicate that a connection was closed abnormally (that is, with no close frame being sent) when a status code is expected.+ | Unsupported_Data+ -- ^ 1007, The endpoint is terminating the connection because a message was received that contained inconsistent data (e.g., nonUTF8 data within a text message).+ | Policy_Violation+ -- ^ 1008, The endpoint is terminating the connection because it received a message that violates its policy. This is a generic status code, used when codes 1003 and 1009 are not suitable.+ | CLOSE_TOO_LARGE+ -- ^ 1009, The endpoint is terminating the connection because a data frame was received that is too large.+ | Missing_Extension+ -- ^ 1010, The client is terminating the connection because it expected the server to negotiate one or more extension, but the server didn't.+ | Internal_Error+ -- ^ 1011, The server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request.+ | Service_Restart+ -- ^ 1012, The server is terminating the connection because it is restarting.+ | Try_Again_Later+ -- ^ 1013, The server is terminating the connection due to a temporary condition, e.g. it is overloaded and is casting off some of its clients.+ | TLS_Handshake+ -- ^ 1015, Reserved. Indicates that the connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can't be verified).+ | OtherCode Int+ -- ^ OtherCode that is reserved and not in the range 0999+ deriving (Show, Eq)+-----------------------------------------------------------------------------+-- | Type for holding a t'WebSocket' file descriptor.+newtype WebSocket = WebSocket Int+ deriving (ToJSVal, Eq, Num)+-----------------------------------------------------------------------------+-- | A null t'WebSocket' is one with a negative descriptor.+emptyWebSocket :: WebSocket+emptyWebSocket = (-1)+-----------------------------------------------------------------------------+-- | A type for holding an t'EventSource' descriptor.+newtype EventSource = EventSource Int+ deriving (ToJSVal, Eq, Num)+-----------------------------------------------------------------------------+-- | A null t'EventSource' is one with a negative descriptor.+emptyEventSource :: EventSource+emptyEventSource = (-1)+-----------------------------------------------------------------------------+eventSourceConnections :: IORef EventSources+{-# NOINLINE eventSourceConnections #-}+eventSourceConnections = unsafePerformIO (newIORef IM.empty)+-----------------------------------------------------------------------------+eventSourceConnectionIds :: IORef Int+{-# NOINLINE eventSourceConnectionIds #-}+eventSourceConnectionIds = unsafePerformIO (newIORef (0 :: Int))+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/EventSource/EventSource>+eventSourceConnectText+ :: URL+ -- ^ EventSource URL+ -> (EventSource -> action)+ -- ^ onOpen+ -> (MisoString -> action)+ -- ^ onMessage+ -> (MisoString -> action)+ -- ^ onError+ -> Effect parent model action+eventSourceConnectText url onOpen onMessage onError =+ eventSourceCore $ \eventSourceId sink -> do+ FFI.eventSourceConnect url+ (sink $ onOpen eventSourceId)+ (pure $ \e -> do+ txt <- fromJSValUnchecked e+ sink (onMessage txt))+ Nothing+ (sink . onError <=< fromJSValUnchecked)+ True+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/EventSource/EventSource>+eventSourceConnectJSON+ :: FromJSON json+ => URL+ -- ^ EventSource URL+ -> (EventSource -> action)+ -- ^ onOpen+ -> (json -> action)+ -- ^ onMessage+ -> (MisoString -> action)+ -- ^ onError+ -> Effect parent model action+eventSourceConnectJSON url onOpen onMessage onError =+ eventSourceCore $ \eventSourceId sink -> do+ FFI.eventSourceConnect url+ (sink $ onOpen eventSourceId)+ Nothing+ (pure $ \e ->+ fromJSON <$> fromJSValUnchecked e >>= \case+ Error errMsg -> sink (onError (ms errMsg))+ Success json_ -> sink $ onMessage json_)+ (sink . onError <=< fromJSValUnchecked)+ False+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/EventSource/EventSource>+eventSourceCore+ :: (EventSource -> Sink action -> IO Socket)+ -> Effect parent model action+eventSourceCore core = do+ ComponentInfo {..} <- ask+ withSink $ \sink -> do+ eventSourceId <- freshEventSource+ socket <- core eventSourceId sink+ insertEventSource _componentInfoId eventSourceId socket+ where+ insertEventSource :: ComponentId -> EventSource -> Socket -> IO ()+ insertEventSource componentId_ (EventSource socketId) socket =+ atomicModifyIORef' eventSourceConnections $ \eventSources ->+ (update eventSources, ())+ where+ update eventSources =+ IM.unionWith IM.union eventSources+ $ IM.singleton componentId_+ $ IM.singleton socketId socket++ freshEventSource :: IO EventSource+ freshEventSource = EventSource <$>+ atomicModifyIORef' eventSourceConnectionIds (\x -> (x + 1, x))+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/EventSource/close>+eventSourceClose :: EventSource -> Effect parent model action+eventSourceClose socketId = do+ ComponentInfo {..} <- ask+ io_ $ do+ result <-+ atomicModifyIORef' eventSourceConnections $ \imap ->+ dropEventSource _componentInfoId socketId imap =:+ getEventSource _componentInfoId socketId imap+ case result of+ Nothing ->+ pure ()+ Just socket ->+ FFI.eventSourceClose socket+ where+ dropEventSource :: ComponentId -> EventSource -> EventSources -> EventSources+ dropEventSource vcompId (EventSource eventSourceId) eventSources = do+ case IM.lookup vcompId eventSources of+ Nothing ->+ eventSources+ Just componentSockets ->+ IM.insert vcompId (IM.delete eventSourceId componentSockets) eventSources++ getEventSource :: ComponentId -> EventSource -> EventSources -> Maybe Socket+ getEventSource vcompId (EventSource eventSourceId) =+ IM.lookup eventSourceId <=< IM.lookup vcompId+-----------------------------------------------------------------------------+finalizeEventSources :: ComponentId -> IO ()+finalizeEventSources vcompId = do+ mapM_ (mapM_ FFI.eventSourceClose . IM.elems) =<<+ IM.lookup vcompId <$> readIORef eventSourceConnections+ dropComponentEventSources+ where+ dropComponentEventSources :: IO ()+ dropComponentEventSources =+ atomicModifyIORef' eventSourceConnections $ \eventSources ->+ (IM.delete vcompId eventSources, ())+-----------------------------------------------------------------------------+-- | Payload is used as the potential source of data when working with t'EventSource'+data Payload value+ = JSON value+ -- ^ JSON-encoded data+ | BLOB Blob+ -- ^ Binary encoded data+ | TEXT MisoString+ -- ^ Text encoded data+ | BUFFER ArrayBuffer+ -- ^ Buffered data+-----------------------------------------------------------------------------+-- | Smart constructor for sending JSON encoded data via an t'EventSource'+json :: ToJSON value => value -> Payload value+json = JSON+-----------------------------------------------------------------------------+-- | Smart constructor for sending binary encoded data via an t'EventSource'+blob :: Blob -> Payload value+blob = BLOB+-----------------------------------------------------------------------------+-- | Smart constructor for sending an @ArrayBuffer@ via an t'EventSource'+arrayBuffer :: ArrayBuffer -> Payload value+arrayBuffer = BUFFER+-----------------------------------------------------------------------------+initComponent+ :: (Eq parent, Eq model)+ => Events+ -> Hydrate+ -> Component parent model action+ -> IO ()+initComponent events hydrate vcomp_@Component {..} = withJS $ do+ root <- Diff.mountElement (getMountPoint mountPoint)+ void $ initialize events rootComponentId hydrate True vcomp_ (pure root)+#if __GLASGOW_HASKELL__ > 865+ flip labelThread "scheduler" =<< forkIO scheduler+#else+ void (forkIO scheduler)+#endif+----------------------------------------------------------------------------+-- | Load miso's javascript.+--+-- You don't need to use this function if you're compiling w/ WASM and using `miso` or `startApp`.+-- It's already invoked for you. This is a no-op w/ the JS backend.+--+-- If you need access to `Miso.FFI` to call functions from `miso.js`, but you're not+-- using `startApp` or `miso`, you'll need to call this function (w/ WASM only).+--+#ifdef PRODUCTION+#define MISO_JS_PATH "js/miso.prod.js"+#else+#define MISO_JS_PATH "js/miso.js"+#endif+withJS+ :: IO a+ -- ^ 'IO' action to execute in between 'evalFile'+ -> IO a+withJS action = do+#ifdef WASM+ $(evalFile MISO_JS_PATH)+#endif+ action+-----------------------------------------------------------------------------
+ src/Miso/Runtime/Internal.hs view
@@ -0,0 +1,31 @@+-----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Runtime.Internal+-- Copyright : (C) 2016-2026 David M. Johnson (@dmjio)+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- This is an internal module not meant for consumption during application+-- development. This is primarily meant to give user's access to the+-- global @component@ state for testing. Use at your own risk. You have been warned.+--+-- We currently consume this module for the miso integration testing package @miso-tests@.+--+-- Alterations to these global variables *will* break your application. Again, do not+-- use these in your main application, only use with the miso testing framework to test+-- your application.+--+----------------------------------------------------------------------------+module Miso.Runtime.Internal+ ( components+ , componentIds+ , rootComponentId+ , ComponentState(..)+ ) where+----------------------------------------------------------------------------+import Miso.Runtime (components, ComponentState(..), componentIds, rootComponentId)+----------------------------------------------------------------------------
+ src/Miso/State.hs view
@@ -0,0 +1,41 @@+-----------------------------------------------------------------------------+-- |+-- Module : Miso.State+-- Copyright : (C) 2016-2026 David M. Johnson (@dmjio)+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- State management for Miso applications.+--+-- Similar to how one manages state in [React](https://react.dev/learn/managing-state),+-- 'Miso.miso' applications manage state with the @State@ monad.+--+-- The @State@ 'Monad' works well with 'Control.Monad.State.Class.MonadState' lenses as seen in [Miso.Lens](https://haddocks.haskell-miso.org) and the [lens](https://hackage.haskell.org/package/lens) library.+--+-- @+-- updateModel :: Action -> Effect parent Model Action+-- updateModel (AddOne event) = do+-- modify (+1)+-- io_ (consoleLog "Added One!")+-- @+--+-- This module re-exports select combinators from 'Control.Monad.RWS' and serves as a placeholder to add new state management combinators.+--+----------------------------------------------------------------------------+module Miso.State+ ( ask+ , asks+ , modify+ , modify'+ , get+ , gets+ , put+ , tell+ , liftIO+ ) where+----------------------------------------------------------------------------+import Control.Monad.RWS (get, gets, modify, modify', tell, put, ask, asks)+import Control.Monad.IO.Class (liftIO)+----------------------------------------------------------------------------
+ src/Miso/Storage.hs view
@@ -0,0 +1,140 @@+-----------------------------------------------------------------------------+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Storage+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- This module provides an interface to the+-- [Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API).+----------------------------------------------------------------------------+module Miso.Storage+ ( -- ** Local+ getLocalStorage+ , setLocalStorage+ , removeLocalStorage+ , clearLocalStorage+ , localStorageLength+ -- ** Session+ , getSessionStorage+ , setSessionStorage+ , removeSessionStorage+ , clearSessionStorage+ , sessionStorageLength+ ) where+-----------------------------------------------------------------------------+import Control.Monad (void)+-----------------------------------------------------------------------------+import Miso.DSL+import Miso.String (MisoString)+-----------------------------------------------------------------------------+-- | Retrieves a value stored under the given key in session storage.+getSessionStorage+ :: MisoString+ -> IO (Maybe MisoString)+getSessionStorage key = do+ fromJSValUnchecked =<< flip getItem key =<< sessionStorage+-----------------------------------------------------------------------------+-- | Retrieves a value stored under the given key in local storage.+getLocalStorage+ :: MisoString+ -> IO (Maybe MisoString)+getLocalStorage key =+ fromJSValUnchecked =<< flip getItem key =<< localStorage+-----------------------------------------------------------------------------+-- | Sets the value of a key in local storage.+--+-- @setLocalStorage key value@ sets the value of @key@ to @value@.+setLocalStorage+ :: MisoString+ -> MisoString+ -> IO ()+setLocalStorage key value = do+ s <- localStorage+ setItem s key value+-----------------------------------------------------------------------------+-- | Sets the value of a key in session storage.+--+-- @setSessionStorage key value@ sets the value of @key@ to @value@.+setSessionStorage+ :: MisoString+ -> MisoString+ -> IO ()+setSessionStorage key value = do+ s <- sessionStorage+ setItem s key value+-----------------------------------------------------------------------------+-- | Removes an item from local storage.+--+-- @removeLocalStorage key@ removes the value of @key@.+removeLocalStorage+ :: MisoString+ -> IO ()+removeLocalStorage key = do+ s <- localStorage+ removeItem s key+-----------------------------------------------------------------------------+-- | Removes an item from session storage.+--+-- @removeSessionStorage key@ removes the value of @key@.+removeSessionStorage+ :: MisoString+ -> IO ()+removeSessionStorage key = do+ s <- sessionStorage+ removeItem s key+-----------------------------------------------------------------------------+-- | Clears local storage.+--+-- @clearLocalStorage@ removes all values from local storage.+clearLocalStorage :: IO ()+clearLocalStorage = clear =<< localStorage+-----------------------------------------------------------------------------+-- | Clears session storage.+--+-- @clearSessionStorage@ removes all values from session storage.+clearSessionStorage :: IO ()+clearSessionStorage = clear =<< sessionStorage+-----------------------------------------------------------------------------+-- | Returns the number of items in local storage.+--+-- @localStorageLength@ returns the count of items in local storage+localStorageLength :: IO Int+localStorageLength = fromJSValUnchecked =<< localStorage ! "length"+-----------------------------------------------------------------------------+-- | Returns the number of items in session storage.+--+-- @sessionStorageLength@ returns the count of items in session storage+sessionStorageLength :: IO Int+sessionStorageLength = fromJSValUnchecked =<< sessionStorage ! "length"+-----------------------------------------------------------------------------+localStorage :: IO Storage+localStorage = Storage <$> (jsg "window" ! "localStorage")+-----------------------------------------------------------------------------+sessionStorage :: IO Storage+sessionStorage = Storage <$> (jsg "window" ! "sessionStorage")+-----------------------------------------------------------------------------+getItem :: Storage -> MisoString -> IO JSVal+getItem (Storage s) key = s # "getItem" $ [key]+-----------------------------------------------------------------------------+removeItem :: Storage -> MisoString -> IO ()+removeItem (Storage s) key = void $ s # "removeItem" $ [key]+-----------------------------------------------------------------------------+setItem :: Storage -> MisoString -> MisoString -> IO ()+setItem (Storage s) key val = do+ _ <- s # "setItem" $ (key, val)+ pure ()+-----------------------------------------------------------------------------+clear :: Storage -> IO ()+clear (Storage s) = do+ _ <- s # "clear" $ ()+ pure ()+-----------------------------------------------------------------------------+newtype Storage = Storage JSVal+ deriving (ToObject, ToJSVal)+-----------------------------------------------------------------------------
+ src/Miso/String.hs view
@@ -0,0 +1,188 @@+-----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE FlexibleInstances #-}+-----------------------------------------------------------------------------+{-# OPTIONS_GHC -fno-warn-orphans #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.String+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+----------------------------------------------------------------------------+module Miso.String+ ( ToMisoString (..)+ , FromMisoString (..)+ , fromMisoString+ , MisoString+#ifdef VANILLA+ , module Data.Text+#else+ , module Data.JSString+#endif+ , ms+ ) where+----------------------------------------------------------------------------+import Control.Exception+import qualified Data.ByteString as B+import qualified Data.ByteString.Builder as B+import qualified Data.ByteString.Lazy as BL+#ifdef VANILLA+import Data.Text hiding (show, elem)+#else+import Data.JSString+#ifdef GHCJS_BOTH+import Data.JSString.Text+#endif+#endif+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.Text.Lazy as LT+import qualified Data.Text.Lazy.Encoding as LT+----------------------------------------------------------------------------+import Miso.DSL.FFI+----------------------------------------------------------------------------+-- | An efficient string type when building miso applications+--+-- t'MisoString' is t'Text' when prerendering+-- t'MisoString' is a JavaScript string when using the JS/WASM backends+--+#ifdef VANILLA+type MisoString = Text+#else+type MisoString = JSString+#endif+----------------------------------------------------------------------------+-- | Convenience class for creating `MisoString` from other string-like types+class ToMisoString str where+ -- | Convert a type into 'MisoString'+ toMisoString :: str -> MisoString+----------------------------------------------------------------------------+-- | Class used to parse a 'MisoString'. Like a safe 'Read' for 'MisoString'+class FromMisoString t where+ fromMisoStringEither :: MisoString -> Either String t+----------------------------------------------------------------------------+-- | Reads a 'MisoString', throws an error when decoding+-- fails. Use `fromMisoStringEither` as a safe alternative.+fromMisoString :: FromMisoString a => MisoString -> a+fromMisoString s =+ case fromMisoStringEither s of+ Left error_ -> error ("fromMisoString: " <> error_)+ Right x -> x+----------------------------------------------------------------------------+-- | Convenience function, shorthand for `toMisoString`+ms :: ToMisoString str => str -> MisoString+ms = toMisoString+----------------------------------------------------------------------------+instance ToMisoString a => ToMisoString (Maybe a) where+ toMisoString = \case+ Nothing -> mempty+ Just x -> ms x+----------------------------------------------------------------------------+instance ToMisoString Char where+ toMisoString = singleton+----------------------------------------------------------------------------+instance ToMisoString IOException where+ toMisoString = ms . show+----------------------------------------------------------------------------+#ifndef VANILLA+instance ToMisoString MisoString where+ toMisoString = id+#endif+----------------------------------------------------------------------------+instance ToMisoString SomeException where+ toMisoString = ms . show+----------------------------------------------------------------------------+instance ToMisoString String where+ toMisoString = pack+----------------------------------------------------------------------------+instance ToMisoString LT.Text where+ toMisoString = ms . LT.toStrict+----------------------------------------------------------------------------+instance ToMisoString T.Text where+#ifdef VANILLA+ toMisoString = id+#else+ toMisoString = textToJSString+#endif+----------------------------------------------------------------------------+instance ToMisoString B.ByteString where+ toMisoString = ms . T.decodeUtf8+----------------------------------------------------------------------------+instance ToMisoString BL.ByteString where+ toMisoString = ms . LT.decodeUtf8+----------------------------------------------------------------------------+instance ToMisoString B.Builder where+ toMisoString = ms . B.toLazyByteString+----------------------------------------------------------------------------+instance ToMisoString Float where+ -- dmj: issue where Float shows additional digits (affects both JS & WASM)+ toMisoString = toString_Double . realToFrac+----------------------------------------------------------------------------+instance ToMisoString Double where+ toMisoString = toString_Double+----------------------------------------------------------------------------+instance ToMisoString Int where+ toMisoString = toString_Int+----------------------------------------------------------------------------+instance ToMisoString Word where+ toMisoString = toString_Word+----------------------------------------------------------------------------+#ifndef VANILLA+instance FromMisoString MisoString where+ fromMisoStringEither = Right+#endif+----------------------------------------------------------------------------+instance FromMisoString T.Text where+#ifdef VANILLA+ fromMisoStringEither = Right+#else+ fromMisoStringEither = Right . textFromJSString+#endif+----------------------------------------------------------------------------+instance FromMisoString String where+ fromMisoStringEither = Right . unpack+----------------------------------------------------------------------------+instance FromMisoString LT.Text where+#ifdef VANILLA+ fromMisoStringEither = Right . LT.fromStrict+#else+ fromMisoStringEither = Right . LT.fromStrict . textFromJSString+#endif+----------------------------------------------------------------------------+instance FromMisoString B.ByteString where+ fromMisoStringEither = fmap T.encodeUtf8 . fromMisoStringEither+----------------------------------------------------------------------------+instance FromMisoString BL.ByteString where+ fromMisoStringEither = fmap LT.encodeUtf8 . fromMisoStringEither+----------------------------------------------------------------------------+instance FromMisoString B.Builder where+ fromMisoStringEither = fmap B.byteString . fromMisoStringEither+----------------------------------------------------------------------------+instance FromMisoString Word where+ fromMisoStringEither string =+ case parseWord string of+ Nothing -> Left ("fromMisoString Word: could not parse " <> unpack string)+ Just x -> Right x+----------------------------------------------------------------------------+instance FromMisoString Double where+ fromMisoStringEither string =+ case parseDouble string of+ Nothing -> Left ("fromMisoString Double: could not parse " <> unpack string)+ Just x -> Right x+----------------------------------------------------------------------------+instance FromMisoString Int where+ fromMisoStringEither string =+ case parseInt string of+ Nothing -> Left ("fromMisoString Int: could not parse " <> unpack string)+ Just x -> Right x+----------------------------------------------------------------------------+instance FromMisoString Float where+ fromMisoStringEither string =+ case parseFloat string of+ Nothing -> Left ("fromMisoString Float: could not parse " <> unpack string)+ Just x -> Right x+----------------------------------------------------------------------------
+ src/Miso/String/QQ.hs view
@@ -0,0 +1,46 @@+-----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskellQuotes #-}+-----------------------------------------------------------------------------+{-# OPTIONS_GHC -Wno-duplicate-exports #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.String.QQ+-- Copyright : (C) 2016-2026 David M. Johnson (@dmjio)+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+----------------------------------------------------------------------------+module Miso.String.QQ+ ( misoString+ ) where+----------------------------------------------------------------------------+import Language.Haskell.TH.Quote+----------------------------------------------------------------------------+import Miso.String (toMisoString)+----------------------------------------------------------------------------+-- | QuasiQuoter for specifying multiline 'Miso.String.MisoString'+--+-- @+-- {-# LANGUAGE QuasiQuotes #-}+--+-- test :: MisoString+-- test = [misoString| foo+-- bar+-- baz+-- |]+--+-- @+--+misoString :: QuasiQuoter+misoString = QuasiQuoter+ { quoteExp = \string -> [| toMisoString string |]+ , quotePat = \_ -> fail "quotePat: not implemented"+ , quoteType = \_ -> fail "quoteType: not implemented"+ , quoteDec = \_ -> fail "quoteDec: not implemented"+ }+----------------------------------------------------------------------------
src/Miso/Subscription.hs view
@@ -1,24 +1,30 @@ ----------------------------------------------------------------------------- -- | -- Module : Miso.Subscription--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable+--+-- Subscriptions for external events (mouse, keyboard, window, history, etc.). ---------------------------------------------------------------------------- module Miso.Subscription- ( module Miso.Subscription.Mouse+ ( -- ** Mouse+ module Miso.Subscription.Mouse+ -- ** Keyboard , module Miso.Subscription.Keyboard+ -- ** History , module Miso.Subscription.History+ -- ** Window , module Miso.Subscription.Window- , module Miso.Subscription.WebSocket- , module Miso.Subscription.SSE+ -- ** OnLine+ , module Miso.Subscription.OnLine ) where-+----------------------------------------------------------------------------- import Miso.Subscription.Mouse import Miso.Subscription.Keyboard import Miso.Subscription.History import Miso.Subscription.Window-import Miso.Subscription.WebSocket-import Miso.Subscription.SSE+import Miso.Subscription.OnLine+-----------------------------------------------------------------------------
src/Miso/Subscription/History.hs view
@@ -1,107 +1,120 @@-{-# LANGUAGE DataKinds #-}+----------------------------------------------------------------------------- {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-} ----------------------------------------------------------------------------- -- | -- Module : Miso.Subscription.History--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable ---------------------------------------------------------------------------- module Miso.Subscription.History- ( getCurrentURI+ ( -- *** Subscription+ uriSub+ , routerSub+ -- *** Functions+ , getURI , pushURI+ , pushRoute , replaceURI , back , forward , go- , uriSub+ -- *** Types , URI (..) ) where--import Control.Monad-import Control.Monad.IO.Class-import Miso.Concurrent-import Miso.Effect (Sub)-import Miso.FFI-import qualified Miso.FFI.History as FFI-import Miso.String-import Network.URI hiding (path)-import System.IO.Unsafe---- | Retrieves current URI of page-getCurrentURI :: JSM URI-{-# INLINE getCurrentURI #-}-getCurrentURI = getURI---- | Retrieves current URI of page-getURI :: JSM URI-{-# INLINE getURI #-}-getURI = do- href <- fromMisoString <$> FFI.getWindowLocationHref- case parseURI href of- Nothing -> fail $ "Could not parse URI from window.location: " ++ href- Just uri -> return uri---- | Pushes a new URI onto the History stack-pushURI :: URI -> JSM ()-{-# INLINE pushURI #-}-pushURI uri = pushStateNoModel uri { uriPath = toPath uri }---- | Prepend '/' if necessary-toPath :: URI -> String-toPath uri =- case uriPath uri of- "" -> "/"- "/" -> "/"- xs@('/' : _) -> xs- xs -> '/' : xs---- | Replaces current URI on stack-replaceURI :: URI -> JSM ()-{-# INLINE replaceURI #-}-replaceURI uri = replaceTo' uri { uriPath = toPath uri }---- | Navigates backwards-back :: JSM ()-{-# INLINE back #-}-back = FFI.back---- | Navigates forwards-forward :: JSM ()-{-# INLINE forward #-}-forward = FFI.forward---- | Jumps to a specific position in history-go :: Int -> JSM ()-{-# INLINE go #-}-go n = FFI.go n--chan :: Notify-{-# NOINLINE chan #-}-chan = unsafePerformIO newEmptyNotify---- | Subscription for @popstate@ events, from the History API+-----------------------------------------------------------------------------+import Control.Monad+-----------------------------------------------------------------------------+import Miso.DSL+import qualified Miso.FFI.Internal as FFI+import Miso.String+import Miso.Router+import Miso.Effect (Sub)+import Miso.Subscription.Util+-----------------------------------------------------------------------------+-- | Pushes a new URI onto the History stack. Also raises a `popstate` event.+pushURI :: URI -> IO ()+pushURI uri = do+ pushState (prettyURI uri)+ raisePopState+-----------------------------------------------------------------------------+-- | Pushes a new 'Route' onto the History stack. Also raises a `popstate` event.+--+-- Converts the t'Route' to a t'URI' internally.+--+pushRoute :: Router route => route -> IO ()+pushRoute = pushURI . toURI+-----------------------------------------------------------------------------+-- | Replaces current URI on stack. Also raises a `popstate` event.+replaceURI :: URI -> IO ()+replaceURI uri = do+ replaceState (prettyURI uri)+ raisePopState+-----------------------------------------------------------------------------+raisePopState :: IO ()+raisePopState = do+ event <- new (jsg "PopStateEvent") ["popstate" :: MisoString]+ window <- jsg "window"+ void $ window # "dispatchEvent" $ [event]+-----------------------------------------------------------------------------+-- | Navigates backwards.+back :: IO ()+back = void $ getHistory # "back" $ ()+-----------------------------------------------------------------------------+-- | Navigates forwards.+forward :: IO ()+forward = void $ getHistory # "forward" $ ()+-----------------------------------------------------------------------------+-- | Jumps to a specific position in history.+go :: Int -> IO ()+go n = void $ getHistory # "go" $ [n]+-----------------------------------------------------------------------------+-- | Subscription for t'URI' changes, uses the History API.+--+-- This returns a new t'URI' whenever `go`, `back`, `forward`, `pushState`+-- or `replaceState` have been called.+-- uriSub :: (URI -> action) -> Sub action-uriSub = \f sink -> do- void.forkJSM.forever $ do- liftIO (wait chan)- liftIO . sink . f =<< getURI- windowAddEventListener "popstate" $ \_ ->- liftIO . sink . f =<< getURI--pushStateNoModel :: URI -> JSM ()-{-# INLINE pushStateNoModel #-}-pushStateNoModel u = do- FFI.pushState . pack . show $ u- liftIO (notify chan)--replaceTo' :: URI -> JSM ()-{-# INLINE replaceTo' #-}-replaceTo' u = do- FFI.replaceState . pack . show $ u- liftIO (notify chan)+uriSub f sink = createSub acquire release sink+ where+ release = FFI.windowRemoveEventListener "popstate"+ acquire = FFI.windowAddEventListener "popstate" $ \_ ->+ (sink =<< f <$> getURI)+-----------------------------------------------------------------------------+-- | Subscription for @popstate@ events, from the History API, mapped+-- to a user-defined 'Router'.+routerSub :: Router route => (Either RoutingError route -> action) -> Sub action+routerSub f = uriSub $ \uri -> f (route uri)+-----------------------------------------------------------------------------+-- | Retrieves the current relative URI by inspecting @pathname@, @search@+-- and @hash@.+getURI :: IO URI+getURI = do+ location <- jsg "window" ! "location"+ pathname <- fromJSValUnchecked =<< location ! "pathname"+ search <- fromJSValUnchecked =<< location ! "search"+ hash <- fromJSValUnchecked =<< location ! "hash"+ let uriText =+ mconcat+ [ pathname+ , search+ , hash+ ]+ case parseURI uriText of+ Left err -> do+ FFI.consoleError ("Couldn't parse URI: " <> err)+ pure emptyURI+ Right uri -> do+ pure uri+-----------------------------------------------------------------------------+getHistory :: IO JSVal+getHistory = jsg "window" ! "history"+-----------------------------------------------------------------------------+pushState :: MisoString -> IO ()+pushState url = void $ getHistory # "pushState" $ (jsNull, jsNull, url)+-----------------------------------------------------------------------------+replaceState :: MisoString -> IO ()+replaceState url = void $ getHistory # "replaceState" $ (jsNull, jsNull, url)+-----------------------------------------------------------------------------
src/Miso/Subscription/Keyboard.hs view
@@ -1,53 +1,52 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE OverloadedStrings #-} -----------------------------------------------------------------------------+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+----------------------------------------------------------------------------- -- | -- Module : Miso.Subscription.Keyboard--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable ---------------------------------------------------------------------------- module Miso.Subscription.Keyboard- ( -- * Types+ ( -- *** Types Arrows (..)- -- * Subscriptions+ -- *** Subscriptions , arrowsSub , directionSub , keyboardSub , wasdSub ) where-+----------------------------------------------------------------------------- import Control.Monad.IO.Class import Data.IORef-import Data.Set-import qualified Data.Set as S-import GHCJS.Marshal-import JavaScript.Object-import JavaScript.Object.Internal-+import Data.IntSet+import qualified Data.IntSet as S+-----------------------------------------------------------------------------+import Miso.DSL hiding (new) import Miso.Effect (Sub)-import Miso.FFI---- | type for arrow keys currently pressed--- 37 left arrow ( x = -1 )--- 38 up arrow ( y = 1 )--- 39 right arrow ( x = 1 )--- 40 down arrow ( y = -1 )-data Arrows = Arrows {- arrowX :: !Int+import Miso.Subscription.Util (createSub)+import qualified Miso.FFI.Internal as FFI+-----------------------------------------------------------------------------+-- | Type for arrow keys currently pressed.+--+-- * 37 left arrow ( x = -1 )+-- * 38 up arrow ( y = 1 )+-- * 39 right arrow ( x = 1 )+-- * 40 down arrow ( y = -1 )+data Arrows+ = Arrows+ { arrowX :: !Int , arrowY :: !Int } deriving (Show, Eq)---- | Helper function to convert keys currently pressed to `Arrow`, given a+-----------------------------------------------------------------------------+-- | Helper function to convert keys currently pressed to @Arrows@, given a -- mapping for keys representing up, down, left and right respectively.-toArrows :: ([Int], [Int], [Int], [Int]) -> Set Int -> Arrows-toArrows (up, down, left, right) set' =- Arrows {- arrowX =+toArrows :: ([Int], [Int], [Int], [Int]) -> IntSet -> Arrows+toArrows (up, down, left, right) set' = Arrows+ { arrowX = case (check left, check right) of (True, False) -> -1 (False, True) -> 1@@ -57,50 +56,60 @@ (True, False) -> -1 (False, True) -> 1 (_,_) -> 0- }- where- check = any (`S.member` set')---- | Maps `Arrows` onto a Keyboard subscription+ } where+ check = any (`S.member` set')+-----------------------------------------------------------------------------+-- | Maps t'Arrows' onto a Keyboard subscription. arrowsSub :: (Arrows -> action) -> Sub action arrowsSub = directionSub ([38], [40], [37], [39])---- | Maps `WASD` onto a Keyboard subscription for directions+-----------------------------------------------------------------------------+-- | Maps t'Arrows' onto a Keyboard subscription for directions (W+A+S+D keys). wasdSub :: (Arrows -> action) -> Sub action wasdSub = directionSub ([87], [83], [65], [68])---- | Maps a specified list of keys to directions (up, down, left, right)-directionSub :: ([Int], [Int], [Int], [Int])- -> (Arrows -> action)- -> Sub action+-----------------------------------------------------------------------------+-- | Maps a specified list of keys to directions (up, down, left, right).+-- The Ints represent [keyCode](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode)s for each direction.+directionSub+ :: ([Int], [Int], [Int], [Int])+ -> (Arrows -> action)+ -> Sub action directionSub dirs = keyboardSub . (. toArrows dirs)---- | Returns subscription for Keyboard-keyboardSub :: (Set Int -> action) -> Sub action-keyboardSub f sink = do- keySetRef <- liftIO (newIORef mempty)- windowAddEventListener "keyup" $ keyUpCallback keySetRef- windowAddEventListener "keydown" $ keyDownCallback keySetRef- windowAddEventListener "blur" $ blurCallback keySetRef- where- keyDownCallback keySetRef = \keyDownEvent -> do- Just key <- fromJSVal =<< getProp "keyCode" (Object keyDownEvent)- newKeys <- liftIO $ atomicModifyIORef' keySetRef $ \keys ->- let !new = S.insert key keys- in (new, new)- liftIO (sink (f newKeys))+-----------------------------------------------------------------------------+-- | Returns 'Sub' for keyboard events.+-- The callback will be called with the Set of currently pressed @keyCode@s.+keyboardSub :: (IntSet -> action) -> Sub action+keyboardSub f sink = createSub acquire release sink+ where+ release (cb1, cb2, cb3) = do+ FFI.windowRemoveEventListener "keyup" cb1+ FFI.windowRemoveEventListener "keydown" cb2+ FFI.windowRemoveEventListener "blur" cb3+ acquire = do+ keySetRef <- liftIO (newIORef mempty)+ cb1 <- FFI.windowAddEventListener "keyup" (keyUpCallback keySetRef)+ cb2 <- FFI.windowAddEventListener "keydown" (keyDownCallback keySetRef)+ cb3 <- FFI.windowAddEventListener "blur" (blurCallback keySetRef)+ pure (cb1, cb2, cb3)+ where+ keyDownCallback keySetRef = \keyDownEvent -> do+ key <- fromJSValUnchecked =<< getProp "keyCode" (Object keyDownEvent)+ newKeys <- liftIO $ atomicModifyIORef' keySetRef $ \keys ->+ let !new = S.insert key keys+ in (new, new)+ sink (f newKeys) - keyUpCallback keySetRef = \keyUpEvent -> do- Just key <- fromJSVal =<< getProp "keyCode" (Object keyUpEvent)- newKeys <- liftIO $ atomicModifyIORef' keySetRef $ \keys ->- let !new = S.delete key keys- in (new, new)- liftIO (sink (f newKeys))+ keyUpCallback keySetRef = \keyUpEvent -> do+ key <- fromJSValUnchecked =<< getProp "keyCode" (Object keyUpEvent)+ newKeys <- liftIO $ atomicModifyIORef' keySetRef $ \keys ->+ let !new = S.delete key keys+ in (new, new)+ sink (f newKeys) - -- Assume keys are released the moment focus is lost. Otherwise going- -- back and forth to the app can cause keys to get stuck.- blurCallback keySetRef = \_ -> do- newKeys <- liftIO $ atomicModifyIORef' keySetRef $ \_ ->- let !new = S.empty- in (new, new)- liftIO (sink (f newKeys))+ -- Assume keys are released the moment focus is lost. Otherwise going+ -- back and forth to the app can cause keys to get stuck.+ blurCallback keySetRef = \_ -> do+ newKeys <- liftIO $ atomicModifyIORef' keySetRef $ \_ ->+ let !new = S.empty+ in (new, new)+ sink (f newKeys)+-----------------------------------------------------------------------------
src/Miso/Subscription/Mouse.hs view
@@ -1,30 +1,25 @@-{-# LANGUAGE RecordWildCards #-}+----------------------------------------------------------------------------- {-# LANGUAGE OverloadedStrings #-} ----------------------------------------------------------------------------- -- | -- Module : Miso.Subscription.Mouse--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable -----------------------------------------------------------------------------module Miso.Subscription.Mouse (mouseSub) where--import Control.Monad.IO.Class-import GHCJS.Marshal-import JavaScript.Object-import JavaScript.Object.Internal-+module Miso.Subscription.Mouse+ ( -- *** Subscription+ mouseSub+ ) where+-----------------------------------------------------------------------------+import Miso.Event (pointerDecoder, PointerEvent)+import Miso.Subscription.Window (windowSub) import Miso.Effect (Sub)-import Miso.FFI-+----------------------------------------------------------------------------- -- | Captures mouse coordinates as they occur and writes them to--- an event sink-mouseSub :: ((Int,Int) -> action) -> Sub action-mouseSub f = \sink -> do- windowAddEventListener "mousemove" $- \mouseEvent -> do- Just x <- fromJSVal =<< getProp "clientX" (Object mouseEvent)- Just y <- fromJSVal =<< getProp "clientY" (Object mouseEvent)- liftIO (sink $ f (x,y))+-- an event sink.+mouseSub :: (PointerEvent -> action) -> Sub action+mouseSub = windowSub "pointermove" pointerDecoder+-----------------------------------------------------------------------------
+ src/Miso/Subscription/OnLine.hs view
@@ -0,0 +1,36 @@+-----------------------------------------------------------------------------+{-# LANGUAGE OverloadedStrings #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Subscription.OnLine+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+----------------------------------------------------------------------------+module Miso.Subscription.OnLine+ ( -- *** Subscriptions+ onLineSub+ ) where+-----------------------------------------------------------------------------+import Miso.Effect (Sub)+import Miso.Subscription.Util (createSub)+import qualified Miso.FFI.Internal as FFI+-----------------------------------------------------------------------------+-- | Returns 'Sub' for the navigator.onLine API.+-- Fires action with 'True' when the browser goes online, and 'False' when it goes offline.+--+-- <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine>+--+onLineSub :: (Bool -> action) -> Sub action+onLineSub f sink = createSub acquire release sink+ where+ release (cb1, cb2) = do+ FFI.windowRemoveEventListener "online" cb1+ FFI.windowRemoveEventListener "offline" cb2+ acquire = do+ cb1 <- FFI.windowAddEventListener "online" (\_ -> sink (f True))+ cb2 <- FFI.windowAddEventListener "offline" (\_ -> sink (f False))+ pure (cb1, cb2)+-----------------------------------------------------------------------------
− src/Miso/Subscription/SSE.hs
@@ -1,49 +0,0 @@-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE LambdaCase #-}--------------------------------------------------------------------------------- |--- Module : Miso.Subscription.SSE--- Copyright : (C) 2016-2025 David M. Johnson--- License : BSD3-style (see the file LICENSE)--- Maintainer : David M. Johnson <code@dmj.io>--- Stability : experimental--- Portability : non-portable------------------------------------------------------------------------------module Miso.Subscription.SSE- ( -- * Subscription- sseSub- -- * Types- , SSE (..)- ) where--import Control.Monad.IO.Class-import Data.Aeson-import Miso.Effect (Sub)-import Miso.FFI-import Miso.String--import qualified Miso.FFI.SSE as SSE---- | Server-sent events Subscription-sseSub :: FromJSON msg => MisoString -> (SSE msg -> action) -> Sub action-sseSub url f = \sink -> do- es <- SSE.new url- SSE.addEventListener es "message" $ \val -> do- dat <- parse =<< SSE.data' val- (liftIO . sink) (f (SSEMessage dat))- SSE.addEventListener es "error" $ \_ ->- (liftIO . sink) (f SSEError)- SSE.addEventListener es "close" $ \_ ->- (liftIO . sink) (f SSEClose)---- | Server-sent events data-data SSE message- = SSEMessage message- | SSEClose- | SSEError- deriving (Show, Eq)---- | Test URL--- http://sapid.sourceforge.net/ssetest/webkit.events.php--- var source = new EventSource("demo_sse.php");
+ src/Miso/Subscription/Util.hs view
@@ -0,0 +1,35 @@+-----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Subscription.Util+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+----------------------------------------------------------------------------+module Miso.Subscription.Util+ ( -- ** Utilities+ createSub+ ) where+----------------------------------------------------------------------------+import Control.Concurrent (threadDelay)+import Control.Monad (forever)+import Control.Exception (bracket)+-----------------------------------------------------------------------------+import Miso.Effect+-----------------------------------------------------------------------------+-- | Utility function to allow resource finalization on 'Sub'.+createSub+ :: IO a+ -- ^ Acquire resource+ -> (a -> IO b)+ -- ^ Release resource+ -> Sub action+createSub acquire release = \_ ->+ bracket acquire release (\_ -> forever (threadDelay (secs 10000)))+ where+ secs :: Int -> Int+ secs = (*1000000)+----------------------------------------------------------------------------
− src/Miso/Subscription/WebSocket.hs
@@ -1,168 +0,0 @@-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE CPP #-}--------------------------------------------------------------------------------- |--- Module : Miso.Subscription.WebSocket--- Copyright : (C) 2016-2025 David M. Johnson--- License : BSD3-style (see the file LICENSE)--- Maintainer : David M. Johnson <code@dmj.io>--- Stability : experimental--- Portability : non-portable------------------------------------------------------------------------------module Miso.Subscription.WebSocket- ( -- * Types- WebSocket (..)- , URL (..)- , Protocols (..)- , SocketState (..)- , CloseCode (..)- , WasClean (..)- , Reason (..)- -- * Subscription- , websocketSub- , send- , close- , connect- , getSocketState- ) where--import Control.Concurrent-import Control.Monad-import Control.Monad.IO.Class-import Data.Aeson-import Data.IORef-import Data.Maybe-import GHCJS.Marshal-import GHCJS.Foreign-import GHCJS.Types ()-import Prelude hiding (map)-import System.IO.Unsafe--import Miso.Effect (Sub)-import Miso.FFI-import Miso.FFI.WebSocket (Socket)-import qualified Miso.FFI.WebSocket as WS-import Miso.String-import Miso.WebSocket--websocket :: IORef (Maybe Socket)-{-# NOINLINE websocket #-}-websocket = unsafePerformIO (newIORef Nothing)--closedCode :: IORef (Maybe CloseCode)-{-# NOINLINE closedCode #-}-closedCode = unsafePerformIO (newIORef Nothing)--secs :: Int -> Int-secs = (*1000000)---- | WebSocket subscription-websocketSub- :: FromJSON m- => URL- -> Protocols- -> (WebSocket m -> action)- -> Sub action-websocketSub (URL u) (Protocols ps) f sink = do- socket <- createWebSocket u ps- liftIO (writeIORef websocket (Just socket))- void . forkJSM $ handleReconnect- WS.addEventListener socket "open" $ \_ -> liftIO $ do- writeIORef closedCode Nothing- sink (f WebSocketOpen)- WS.addEventListener socket "message" $ \v -> do- d <- parse =<< WS.data' v- liftIO . sink $ f (WebSocketMessage d)- WS.addEventListener socket "close" $ \e -> do- code <- codeToCloseCode <$> WS.code e- liftIO (writeIORef closedCode (Just code))- reason <- WS.reason e- clean <- WS.wasClean e- liftIO . sink $ f (WebSocketClose code clean reason)- WS.addEventListener socket "error" $ \v -> do- liftIO (writeIORef closedCode Nothing)- d' <- WS.data' v-#ifndef ghcjs_HOST_OS- undef <- ghcjsPure (isUndefined d')-#else- let undef = isUndefined d'-#endif- if undef- then do- liftIO . sink $ f (WebSocketError mempty)- else do- Just d <- fromJSVal d'- liftIO . sink $ f (WebSocketError d)- where- handleReconnect = do- liftIO (threadDelay (secs 3))- Just s <- liftIO (readIORef websocket)- status <- WS.socketState s- code <- liftIO (readIORef closedCode)- if status == 3- then do- unless (code == Just CLOSE_NORMAL) $- websocketSub (URL u) (Protocols ps) f sink- else handleReconnect---- | Sends message to a websocket server-send :: ToJSON a => a -> JSM ()-{-# INLINE send #-}-send x = do- Just socket <- liftIO (readIORef websocket)- sendJson' socket x---- | Sends message to a websocket server-close :: JSM ()-{-# INLINE close #-}-close =- mapM_ WS.close =<<- liftIO (readIORef websocket)---- | Connects to a websocket server-connect :: URL -> Protocols -> JSM ()-{-# INLINE connect #-}-connect (URL url') (Protocols ps) = do- Just ws <- liftIO (readIORef websocket)- s <- WS.socketState ws- when (s == 3) $ do- socket <- createWebSocket url' ps- liftIO (atomicWriteIORef websocket (Just socket))---- | Retrieves current status of `WebSocket`-getSocketState :: JSM SocketState-getSocketState = do- Just ws <- liftIO (readIORef websocket)- toEnum <$> WS.socketState ws--sendJson' :: ToJSON json => Socket -> json -> JSM ()-sendJson' socket m = WS.send socket =<< stringify m--createWebSocket :: MisoString -> [MisoString] -> JSM Socket-{-# INLINE createWebSocket #-}-createWebSocket url' protocols =- WS.create url' =<< toJSVal protocols--codeToCloseCode :: Int -> CloseCode-codeToCloseCode = go- where- go 1000 = CLOSE_NORMAL- go 1001 = CLOSE_GOING_AWAY- go 1002 = CLOSE_PROTOCOL_ERROR- go 1003 = CLOSE_UNSUPPORTED- go 1005 = CLOSE_NO_STATUS- go 1006 = CLOSE_ABNORMAL- go 1007 = Unsupported_Data- go 1008 = Policy_Violation- go 1009 = CLOSE_TOO_LARGE- go 1010 = Missing_Extension- go 1011 = Internal_Error- go 1012 = Service_Restart- go 1013 = Try_Again_Later- go 1015 = TLS_Handshake- go n = OtherCode n
src/Miso/Subscription/Window.hs view
@@ -1,58 +1,73 @@+----------------------------------------------------------------------------- {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE OverloadedStrings #-} ----------------------------------------------------------------------------- -- | -- Module : Miso.Subscription.Window--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable -----------------------------------------------------------------------------module Miso.Subscription.Window where--import Control.Monad-import Control.Monad.IO.Class--import GHCJS.Marshal-import JavaScript.Object-import JavaScript.Object.Internal--import Miso.Effect (Sub)-import Miso.Event-import Miso.FFI-import Miso.String--import Data.Aeson.Types (parseEither)-+module Miso.Subscription.Window+ ( -- *** Subscription+ windowSub+ , windowCoordsSub+ , windowPointerMoveSub+ , windowSubWithOptions+ -- *** Types+ , Coord+ ) where+-----------------------------------------------------------------------------+import Control.Monad+-----------------------------------------------------------------------------+import Miso.DSL+import Miso.Event+import Miso.Effect+import qualified Miso.FFI.Internal as FFI+import Miso.JSON hiding (Options, defaultOptions)+import Miso.String+import Miso.Subscription.Util+import Miso.Canvas (Coord)+----------------------------------------------------------------------------- -- | Captures window coordinates changes as they occur and writes them to--- an event sink-windowCoordsSub :: ((Int, Int) -> action) -> Sub action-windowCoordsSub f = \sink -> do- liftIO . sink . f =<< (,) <$> windowInnerHeight <*> windowInnerWidth- windowAddEventListener "resize" $- \windowEvent -> do- target <- getProp "target" (Object windowEvent)- Just w <- fromJSVal =<< getProp "innerWidth" (Object target)- Just h <- fromJSVal =<< getProp "innerHeight" (Object target)- liftIO . sink $ f (h, w)---- | @windowSub eventName decoder toAction@ is a subscription which parallels the--- attribute handler `on`, providing a subscription to listen to window level events.+-- an event sink.+windowCoordsSub :: (Coord -> action) -> Sub action+windowCoordsSub f = windowPointerMoveSub (f . client)+-----------------------------------------------------------------------------+-- | @windowSub eventName decoder toAction@ provides a subscription+-- to listen to [window level events](https://developer.mozilla.org/en-US/docs/Web/API/Window#events). windowSub :: MisoString -> Decoder r -> (r -> action) -> Sub action-windowSub = windowSubWithOptions defaultOptions---- | @windowSubWithOptions options eventName decoder toAction@ is a subscription which parallels the--- attribute handler `on`, providing a subscription to listen to window level events.-windowSubWithOptions :: Options -> MisoString -> Decoder r -> (r -> action) -> Sub action-windowSubWithOptions Options{..} eventName Decoder{..} toAction = \sink -> do- windowAddEventListener eventName $- \e -> do- decodeAtVal <- toJSVal decodeAt- Just v <- fromJSVal =<< objectToJSON decodeAtVal e- case parseEither decoder v of- Left s -> error $ "Parse error on " <> unpack eventName <> ": " <> s- Right r -> do- when stopPropagation $ eventStopPropagation e- when preventDefault $ eventPreventDefault e- liftIO (sink (toAction r))+windowSub = windowSubWithOptions defaultOptions+-----------------------------------------------------------------------------+-- | @windowSubWithOptions options eventName decoder toAction@ provides a+-- subscription to listen to [window level events](https://developer.mozilla.org/en-US/docs/Web/API/Window#events).+windowSubWithOptions+ :: Options+ -> MisoString+ -> Decoder result+ -> (result -> action)+ -> Sub action+windowSubWithOptions Options{..} eventName Decoder {..} toAction sink =+ createSub acquire release sink+ where+ release =+ FFI.windowRemoveEventListener eventName+ acquire =+ FFI.windowAddEventListener eventName $ \e -> do+ decodeAtVal <- toJSVal decodeAt+ v <- fromJSValUnchecked =<< FFI.eventJSON decodeAtVal e+ case parseEither decoder v of+ Left s ->+ FFI.consoleError ("windowSubWithOptions: Parse error on " <> eventName <> ": " <> ms s)+ Right r -> do+ when _stopPropagation (FFI.eventStopPropagation e)+ when _preventDefault (FFI.eventPreventDefault e)+ sink (toAction r)+-----------------------------------------------------------------------------+-- | @window.addEventListener ("pointermove", (event) => handle(event))@+-- A 'Sub' to handle t'PointerEvent's on window.+windowPointerMoveSub :: (PointerEvent -> action) -> Sub action+windowPointerMoveSub = windowSub "pointermove" pointerDecoder+-----------------------------------------------------------------------------
src/Miso/Svg.hs view
@@ -1,7 +1,7 @@ ----------------------------------------------------------------------------- -- | -- Module : Miso.Svg--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental@@ -13,25 +13,24 @@ -- import Miso -- import Miso.Svg ----- intView :: Int -> View IntAction--- intView n = svg_ [ height_ "100", width "100" ] [+-- view_ :: Int -> View Int action+-- view_ n = svg_ [ height_ "100", width "100" ] [ -- circle_ [ cx_ "50", cy_ "50", r_ "40", stroke_ "green", strokeWidth_ "4", fill_ "yellow" ] [] -- ] -- @ ----- More information on how to use `miso` is available on GitHub+-- More information on how to use miso is available on GitHub -- -- <http://github.com/dmjio/miso> -- ---------------------------------------------------------------------------- module Miso.Svg- ( module Miso.Svg.Element- , module Miso.Svg.Attribute+ ( -- ** Element+ module Miso.Svg.Element+ -- ** Event , module Miso.Svg.Event ) where--import Miso.Svg.Attribute hiding ( filter_, path_, title_, mask_- , glyphRef_, clipPath_, colorProfile_- , cursor_, style_ )+----------------------------------------------------------------------------- import Miso.Svg.Element import Miso.Svg.Event+-----------------------------------------------------------------------------
− src/Miso/Svg/Attribute.hs
@@ -1,1038 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE OverloadedStrings #-}--------------------------------------------------------------------------------- |--- Module : Miso.Svg.Attribute--- Copyright : (C) 2016-2025 David M. Johnson--- License : BSD3-style (see the file LICENSE)--- Maintainer : David M. Johnson <code@dmj.io>--- Stability : experimental--- Portability : non-portable------ <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute>---------------------------------------------------------------------------------module Miso.Svg.Attribute- ( -- * Regular attributes- accentHeight_- , accelerate_- , accumulate_- , additive_- , alphabetic_- , allowReorder_- , amplitude_- , arabicForm_- , ascent_- , attributeName_- , attributeType_- , autoReverse_- , azimuth_- , baseFrequency_- , baseProfile_- , bbox_- , begin_- , bias_- , by_- , calcMode_- , capHeight_- , class_'- , clipPathUnits_- , contentScriptType_- , contentStyleType_- , cx_- , cy_- , d_- , decelerate_- , descent_- , diffuseConstant_- , divisor_- , dur_- , dx_- , dy_- , edgeMode_- , elevation_- , end_- , exponent_- , externalResourcesRequired_- , filterRes_- , filterUnits_- , format_- , from_- , fx_- , fy_- , g1_- , g2_- , glyphName_- , glyphRef_- , gradientTransform_- , gradientUnits_- , hanging_- , height_- , horizAdvX_- , horizOriginX_- , horizOriginY_- , id_- , ideographic_- , in_'- , in2_- , intercept_- , k_- , k1_- , k2_- , k3_- , k4_- , kernelMatrix_- , kernelUnitLength_- , keyPoints_- , keySplines_- , keyTimes_- , lang_- , lengthAdjust_- , limitingConeAngle_- , local_- , markerHeight_- , markerUnits_- , markerWidth_- , maskContentUnits_- , maskUnits_- , mathematical_- , max_- , media_- , method_- , min_- , mode_- , name_- , numOctaves_- , offset_- , operator_- , order_- , orient_- , orientation_- , origin_- , overlinePosition_- , overlineThickness_- , panose1_- , path_- , pathLength_- , patternContentUnits_- , patternTransform_- , patternUnits_- , pointOrder_- , points_- , pointsAtX_- , pointsAtY_- , pointsAtZ_- , preserveAlpha_- , preserveAspectRatio_- , primitiveUnits_- , r_- , radius_- , refX_- , refY_- , renderingIntent_- , repeatCount_- , repeatDur_- , requiredExtensions_- , requiredFeatures_- , restart_- , result_- , rotate_- , rx_- , ry_- , scale_- , seed_- , slope_- , spacing_- , specularConstant_- , specularExponent_- , speed_- , spreadMethod_- , startOffset_- , stdDeviation_- , stemh_- , stemv_- , stitchTiles_- , strikethroughPosition_- , strikethroughThickness_- , string_- , style_- , surfaceScale_- , systemLanguage_- , tableValues_- , target_- , targetX_- , targetY_- , textLength_- , title_- , to_- , transform_- , type_'- , u1_- , u2_- , underlinePosition_- , underlineThickness_- , unicode_- , unicodeRange_- , unitsPerEm_- , vAlphabetic_- , vHanging_- , vIdeographic_- , vMathematical_- , values_- , version_- , vertAdvY_- , vertOriginX_- , vertOriginY_- , viewBox_- , viewTarget_- , width_- , widths_- , x_- , xHeight_- , x1_- , x2_- , xChannelSelector_- , xlinkActuate_- , xlinkArcrole_- , xlinkHref_- , xlinkRole_- , xlinkShow_- , xlinkTitle_- , xlinkType_- , xmlBase_- , xmlLang_- , xmlSpace_- , y_- , y1_- , y2_- , yChannelSelector_- , z_- , zoomAndPan_- -- * Presentation_ attributes- , alignmentBaseline_- , baselineShift_- , clipPath_- , clipRule_- , clip_- , colorInterpolationFilters_- , colorInterpolation_- , colorProfile_- , colorRendering_- , color_- , cursor_- , direction_- , display_- , dominantBaseline_- , enableBackground_- , fillOpacity_- , fillRule_- , fill_- , filter_- , floodColor_- , floodOpacity_- , fontFamily_- , fontSizeAdjust_- , fontSize_- , fontStretch_- , fontStyle_- , fontVariant_- , fontWeight_- , glyphOrientationHorizontal_- , glyphOrientationVertical_- , imageRendering_- , kerning_- , letterSpacing_- , lightingColor_- , markerEnd_- , markerMid_- , markerStart_- , mask_- , opacity_- , overflow_- , pointerEvents_- , shapeRendering_- , stopColor_- , stopOpacity_- , strokeDasharray_- , strokeDashoffset_- , strokeLinecap_- , strokeLinejoin_- , strokeMiterlimit_- , strokeOpacity_- , strokeWidth_- , stroke_- , textAnchor_- , textDecoration_- , textRendering_- , unicodeBidi_- , visibility_- , wordSpacing_- , writingMode_- ) where--import Miso.Html.Types ( Attribute )-import Miso.Html.Property ( textProp )-import Miso.String ( MisoString )--attr :: MisoString -> MisoString -> Attribute action-attr = textProp---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/accent-height>-accentHeight_ :: MisoString -> Attribute action-accentHeight_ = attr "accent-height"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/accelerate>-accelerate_ :: MisoString -> Attribute action-accelerate_ = attr "accelerate"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/accumulate>-accumulate_ :: MisoString -> Attribute action-accumulate_ = attr "accumulate"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/additive>-additive_ :: MisoString -> Attribute action-additive_ = attr "additive"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/alphabetic>-alphabetic_ :: MisoString -> Attribute action-alphabetic_ = attr "alphabetic"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/allowReorder>-allowReorder_ :: MisoString -> Attribute action-allowReorder_ = attr "allowReorder"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/amplitude>-amplitude_ :: MisoString -> Attribute action-amplitude_ = attr "amplitude"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/arabic-form>-arabicForm_ :: MisoString -> Attribute action-arabicForm_ = attr "arabic-form"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/ascent>-ascent_ :: MisoString -> Attribute action-ascent_ = attr "ascent"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/attributeName>-attributeName_ :: MisoString -> Attribute action-attributeName_ = attr "attributeName"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/attributeType>-attributeType_ :: MisoString -> Attribute action-attributeType_ = attr "attributeType"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/autoReverse>-autoReverse_ :: MisoString -> Attribute action-autoReverse_ = attr "autoReverse"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/azimuth>-azimuth_ :: MisoString -> Attribute action-azimuth_ = attr "azimuth"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/baseFrequency>-baseFrequency_ :: MisoString -> Attribute action-baseFrequency_ = attr "baseFrequency"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/baseProfile>-baseProfile_ :: MisoString -> Attribute action-baseProfile_ = attr "baseProfile"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/bbox>-bbox_ :: MisoString -> Attribute action-bbox_ = attr "bbox"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/begin>-begin_ :: MisoString -> Attribute action-begin_ = attr "begin"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/bias>-bias_ :: MisoString -> Attribute action-bias_ = attr "bias"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/by>-by_ :: MisoString -> Attribute action-by_ = attr "by"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/calcMode>-calcMode_ :: MisoString -> Attribute action-calcMode_ = attr "calcMode"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/cap-height>-capHeight_ :: MisoString -> Attribute action-capHeight_ = attr "cap-height"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/class>-class_' :: MisoString -> Attribute action-class_' = attr "class"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/clipPathUnits>-clipPathUnits_ :: MisoString -> Attribute action-clipPathUnits_ = attr "clipPathUnits"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/contentScriptType>-contentScriptType_ :: MisoString -> Attribute action-contentScriptType_ = attr "contentScriptType"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/contentStyleType>-contentStyleType_ :: MisoString -> Attribute action-contentStyleType_ = attr "contentStyleType"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/cx>-cx_ :: MisoString -> Attribute action-cx_ = attr "cx"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/cy>-cy_ :: MisoString -> Attribute action-cy_ = attr "cy"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d>-d_ :: MisoString -> Attribute action-d_ = attr "d"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/decelerate>-decelerate_ :: MisoString -> Attribute action-decelerate_ = attr "decelerate"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/descent>-descent_ :: MisoString -> Attribute action-descent_ = attr "descent"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/diffuseConstant>-diffuseConstant_ :: MisoString -> Attribute action-diffuseConstant_ = attr "diffuseConstant"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/divisor>-divisor_ :: MisoString -> Attribute action-divisor_ = attr "divisor"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/dur>-dur_ :: MisoString -> Attribute action-dur_ = attr "dur"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/dx>-dx_ :: MisoString -> Attribute action-dx_ = attr "dx"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/dy>-dy_ :: MisoString -> Attribute action-dy_ = attr "dy"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/edgeMode>-edgeMode_ :: MisoString -> Attribute action-edgeMode_ = attr "edgeMode"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/elevation>-elevation_ :: MisoString -> Attribute action-elevation_ = attr "elevation"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/end>-end_ :: MisoString -> Attribute action-end_ = attr "end"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/exponent>-exponent_ :: MisoString -> Attribute action-exponent_ = attr "exponent"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/externalResourcesRequired>-externalResourcesRequired_ :: MisoString -> Attribute action-externalResourcesRequired_ = attr "externalResourcesRequired"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/filterRes>-filterRes_ :: MisoString -> Attribute action-filterRes_ = attr "filterRes"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/filterUnits>-filterUnits_ :: MisoString -> Attribute action-filterUnits_ = attr "filterUnits"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/format>-format_ :: MisoString -> Attribute action-format_ = attr "format"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/from>-from_ :: MisoString -> Attribute action-from_ = attr "from"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fx>-fx_ :: MisoString -> Attribute action-fx_ = attr "fx"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fy>-fy_ :: MisoString -> Attribute action-fy_ = attr "fy"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/g1>-g1_ :: MisoString -> Attribute action-g1_ = attr "g1"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/g2>-g2_ :: MisoString -> Attribute action-g2_ = attr "g2"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/glyph-name>-glyphName_ :: MisoString -> Attribute action-glyphName_ = attr "glyph-name"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/glyphRef>-glyphRef_ :: MisoString -> Attribute action-glyphRef_ = attr "glyphRef"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/gradientTransform>-gradientTransform_ :: MisoString -> Attribute action-gradientTransform_ = attr "gradientTransform"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/gradientUnits>-gradientUnits_ :: MisoString -> Attribute action-gradientUnits_ = attr "gradientUnits"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/hanging>-hanging_ :: MisoString -> Attribute action-hanging_ = attr "hanging"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/height>-height_ :: MisoString -> Attribute action-height_ = attr "height"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/horiz-adv-x>-horizAdvX_ :: MisoString -> Attribute action-horizAdvX_ = attr "horiz-adv-x"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/horiz-origin-x>-horizOriginX_ :: MisoString -> Attribute action-horizOriginX_ = attr "horiz-origin-x"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/horiz-origin-y>-horizOriginY_ :: MisoString -> Attribute action-horizOriginY_ = attr "horiz-origin-y"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/id>-id_ :: MisoString -> Attribute action-id_ = attr "id"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/ideographic>-ideographic_ :: MisoString -> Attribute action-ideographic_ = attr "ideographic"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/in>-in_' :: MisoString -> Attribute action-in_' = attr "in"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/in2>-in2_ :: MisoString -> Attribute action-in2_ = attr "in2"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/intercept>-intercept_ :: MisoString -> Attribute action-intercept_ = attr "intercept"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/k>-k_ :: MisoString -> Attribute action-k_ = attr "k"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/k1>-k1_ :: MisoString -> Attribute action-k1_ = attr "k1"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/k2>-k2_ :: MisoString -> Attribute action-k2_ = attr "k2"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/k3>-k3_ :: MisoString -> Attribute action-k3_ = attr "k3"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/k4>-k4_ :: MisoString -> Attribute action-k4_ = attr "k4"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/kernelMatrix>-kernelMatrix_ :: MisoString -> Attribute action-kernelMatrix_ = attr "kernelMatrix"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/kernelUnitLength>-kernelUnitLength_ :: MisoString -> Attribute action-kernelUnitLength_ = attr "kernelUnitLength"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/keyPoints>-keyPoints_ :: MisoString -> Attribute action-keyPoints_ = attr "keyPoints"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/keySplines>-keySplines_ :: MisoString -> Attribute action-keySplines_ = attr "keySplines"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/keyTimes>-keyTimes_ :: MisoString -> Attribute action-keyTimes_ = attr "keyTimes"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/lang>-lang_ :: MisoString -> Attribute action-lang_ = attr "lang"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/lengthAdjust>-lengthAdjust_ :: MisoString -> Attribute action-lengthAdjust_ = attr "lengthAdjust"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/limitingConeAngle>-limitingConeAngle_ :: MisoString -> Attribute action-limitingConeAngle_ = attr "limitingConeAngle"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/local>-local_ :: MisoString -> Attribute action-local_ = attr "local"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/markerHeight>-markerHeight_ :: MisoString -> Attribute action-markerHeight_ = attr "markerHeight"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/markerUnits>-markerUnits_ :: MisoString -> Attribute action-markerUnits_ = attr "markerUnits"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/markerWidth>-markerWidth_ :: MisoString -> Attribute action-markerWidth_ = attr "markerWidth"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/maskContentUnits>-maskContentUnits_ :: MisoString -> Attribute action-maskContentUnits_ = attr "maskContentUnits"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/maskUnits>-maskUnits_ :: MisoString -> Attribute action-maskUnits_ = attr "maskUnits"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/mathematical>-mathematical_ :: MisoString -> Attribute action-mathematical_ = attr "mathematical"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/max>-max_ :: MisoString -> Attribute action-max_ = attr "max"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/media>-media_ :: MisoString -> Attribute action-media_ = attr "media"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/method>-method_ :: MisoString -> Attribute action-method_ = attr "method"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/min>-min_ :: MisoString -> Attribute action-min_ = attr "min"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/mode>-mode_ :: MisoString -> Attribute action-mode_ = attr "mode"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/name>-name_ :: MisoString -> Attribute action-name_ = attr "name"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/numOctaves>-numOctaves_ :: MisoString -> Attribute action-numOctaves_ = attr "numOctaves"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/offset>-offset_ :: MisoString -> Attribute action-offset_ = attr "offset"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/operator>-operator_ :: MisoString -> Attribute action-operator_ = attr "operator"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/order>-order_ :: MisoString -> Attribute action-order_ = attr "order"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/orient>-orient_ :: MisoString -> Attribute action-orient_ = attr "orient"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/orientation>-orientation_ :: MisoString -> Attribute action-orientation_ = attr "orientation"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/origin>-origin_ :: MisoString -> Attribute action-origin_ = attr "origin"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/overline-position>-overlinePosition_ :: MisoString -> Attribute action-overlinePosition_ = attr "overline-position"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/overline-thickness>-overlineThickness_ :: MisoString -> Attribute action-overlineThickness_ = attr "overline-thickness"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/panose-1>-panose1_ :: MisoString -> Attribute action-panose1_ = attr "panose-1"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/path>-path_ :: MisoString -> Attribute action-path_ = attr "path"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pathLength>-pathLength_ :: MisoString -> Attribute action-pathLength_ = attr "pathLength"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/patternContentUnits>-patternContentUnits_ :: MisoString -> Attribute action-patternContentUnits_ = attr "patternContentUnits"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/patternTransform>-patternTransform_ :: MisoString -> Attribute action-patternTransform_ = attr "patternTransform"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/patternUnits>-patternUnits_ :: MisoString -> Attribute action-patternUnits_ = attr "patternUnits"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/point-order>-pointOrder_ :: MisoString -> Attribute action-pointOrder_ = attr "point-order"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/points>-points_ :: MisoString -> Attribute action-points_ = attr "points"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointsAtX>-pointsAtX_ :: MisoString -> Attribute action-pointsAtX_ = attr "pointsAtX"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointsAtY>-pointsAtY_ :: MisoString -> Attribute action-pointsAtY_ = attr "pointsAtY"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointsAtZ>-pointsAtZ_ :: MisoString -> Attribute action-pointsAtZ_ = attr "pointsAtZ"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAlpha>-preserveAlpha_ :: MisoString -> Attribute action-preserveAlpha_ = attr "preserveAlpha"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio>-preserveAspectRatio_ :: MisoString -> Attribute action-preserveAspectRatio_ = attr "preserveAspectRatio"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/primitiveUnits>-primitiveUnits_ :: MisoString -> Attribute action-primitiveUnits_ = attr "primitiveUnits"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/r>-r_ :: MisoString -> Attribute action-r_ = attr "r"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/radius>-radius_ :: MisoString -> Attribute action-radius_ = attr "radius"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/refX>-refX_ :: MisoString -> Attribute action-refX_ = attr "refX"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/refY>-refY_ :: MisoString -> Attribute action-refY_ = attr "refY"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/rendering-intent>-renderingIntent_ :: MisoString -> Attribute action-renderingIntent_ = attr "rendering-intent"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/repeatCount>-repeatCount_ :: MisoString -> Attribute action-repeatCount_ = attr "repeatCount"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/repeatDur>-repeatDur_ :: MisoString -> Attribute action-repeatDur_ = attr "repeatDur"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/requiredExtensions>-requiredExtensions_ :: MisoString -> Attribute action-requiredExtensions_ = attr "requiredExtensions"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/requiredFeatures>-requiredFeatures_ :: MisoString -> Attribute action-requiredFeatures_ = attr "requiredFeatures"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/restart>-restart_ :: MisoString -> Attribute action-restart_ = attr "restart"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/result>-result_ :: MisoString -> Attribute action-result_ = attr "result"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/rotate>-rotate_ :: MisoString -> Attribute action-rotate_ = attr "rotate"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/rx>-rx_ :: MisoString -> Attribute action-rx_ = attr "rx"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/ry>-ry_ :: MisoString -> Attribute action-ry_ = attr "ry"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/scale>-scale_ :: MisoString -> Attribute action-scale_ = attr "scale"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/seed>-seed_ :: MisoString -> Attribute action-seed_ = attr "seed"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/slope>-slope_ :: MisoString -> Attribute action-slope_ = attr "slope"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/spacing>-spacing_ :: MisoString -> Attribute action-spacing_ = attr "spacing"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/specularConstant>-specularConstant_ :: MisoString -> Attribute action-specularConstant_ = attr "specularConstant"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/specularExponent>-specularExponent_ :: MisoString -> Attribute action-specularExponent_ = attr "specularExponent"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/speed>-speed_ :: MisoString -> Attribute action-speed_ = attr "speed"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/spreadMethod>-spreadMethod_ :: MisoString -> Attribute action-spreadMethod_ = attr "spreadMethod"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/startOffset>-startOffset_ :: MisoString -> Attribute action-startOffset_ = attr "startOffset"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stdDeviation>-stdDeviation_ :: MisoString -> Attribute action-stdDeviation_ = attr "stdDeviation"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stemh>-stemh_ :: MisoString -> Attribute action-stemh_ = attr "stemh"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stemv>-stemv_ :: MisoString -> Attribute action-stemv_ = attr "stemv"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stitchTiles>-stitchTiles_ :: MisoString -> Attribute action-stitchTiles_ = attr "stitchTiles"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/strikethrough-position>-strikethroughPosition_ :: MisoString -> Attribute action-strikethroughPosition_ = attr "strikethrough-position"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/strikethrough-thickness>-strikethroughThickness_ :: MisoString -> Attribute action-strikethroughThickness_ = attr "strikethrough-thickness"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/string>-string_ :: MisoString -> Attribute action-string_ = attr "string"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/style>-style_ :: MisoString -> Attribute action-style_ = attr "style"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/surfaceScale>-surfaceScale_ :: MisoString -> Attribute action-surfaceScale_ = attr "surfaceScale"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/systemLanguage>-systemLanguage_ :: MisoString -> Attribute action-systemLanguage_ = attr "systemLanguage"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/tableValues>-tableValues_ :: MisoString -> Attribute action-tableValues_ = attr "tableValues"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/target>-target_ :: MisoString -> Attribute action-target_ = attr "target"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/targetX>-targetX_ :: MisoString -> Attribute action-targetX_ = attr "targetX"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/targetY>-targetY_ :: MisoString -> Attribute action-targetY_ = attr "targetY"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/textLength>-textLength_ :: MisoString -> Attribute action-textLength_ = attr "textLength"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/title>-title_ :: MisoString -> Attribute action-title_ = attr "title"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/to>-to_ :: MisoString -> Attribute action-to_ = attr "to"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform>-transform_ :: MisoString -> Attribute action-transform_ = attr "transform"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/type>-type_' :: MisoString -> Attribute action-type_' = attr "type"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/u1>-u1_ :: MisoString -> Attribute action-u1_ = attr "u1"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/u2>-u2_ :: MisoString -> Attribute action-u2_ = attr "u2"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/underline-position>-underlinePosition_ :: MisoString -> Attribute action-underlinePosition_ = attr "underline-position"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/underline-thickness>-underlineThickness_ :: MisoString -> Attribute action-underlineThickness_ = attr "underline-thickness"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/unicode>-unicode_ :: MisoString -> Attribute action-unicode_ = attr "unicode"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/unicode-range>-unicodeRange_ :: MisoString -> Attribute action-unicodeRange_ = attr "unicode-range"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/units-per-em>-unitsPerEm_ :: MisoString -> Attribute action-unitsPerEm_ = attr "units-per-em"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/v-alphabetic>-vAlphabetic_ :: MisoString -> Attribute action-vAlphabetic_ = attr "v-alphabetic"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/v-hanging>-vHanging_ :: MisoString -> Attribute action-vHanging_ = attr "v-hanging"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/v-ideographic>-vIdeographic_ :: MisoString -> Attribute action-vIdeographic_ = attr "v-ideographic"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/v-mathematical>-vMathematical_ :: MisoString -> Attribute action-vMathematical_ = attr "v-mathematical"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/values>-values_ :: MisoString -> Attribute action-values_ = attr "values"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/version>-version_ :: MisoString -> Attribute action-version_ = attr "version"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/vert-adv-y>-vertAdvY_ :: MisoString -> Attribute action-vertAdvY_ = attr "vert-adv-y"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/vert-origin-x>-vertOriginX_ :: MisoString -> Attribute action-vertOriginX_ = attr "vert-origin-x"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/vert-origin-y>-vertOriginY_ :: MisoString -> Attribute action-vertOriginY_ = attr "vert-origin-y"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox>-viewBox_ :: MisoString -> Attribute action-viewBox_ = attr "viewBox"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewTarget>-viewTarget_ :: MisoString -> Attribute action-viewTarget_ = attr "viewTarget"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width>-width_ :: MisoString -> Attribute action-width_ = attr "width"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/widths>-widths_ :: MisoString -> Attribute action-widths_ = attr "widths"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/x>-x_ :: MisoString -> Attribute action-x_ = attr "x"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/x-height>-xHeight_ :: MisoString -> Attribute action-xHeight_ = attr "x-height"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/x1>-x1_ :: MisoString -> Attribute action-x1_ = attr "x1"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/x2>-x2_ :: MisoString -> Attribute action-x2_ = attr "x2"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xChannelSelector>-xChannelSelector_ :: MisoString -> Attribute action-xChannelSelector_ = attr "x-channel-selector"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlinkActuate>-xlinkActuate_ :: MisoString -> Attribute action-xlinkActuate_ = attr "xlinkActuate"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlinkArcrole>-xlinkArcrole_ :: MisoString -> Attribute action-xlinkArcrole_ = attr "xlinkArcrole"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlinkHref>-xlinkHref_ :: MisoString -> Attribute action-xlinkHref_ = attr "xlinkHref"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlinkRole>-xlinkRole_ :: MisoString -> Attribute action-xlinkRole_ = attr "xlinkRole"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlinkShow>-xlinkShow_ :: MisoString -> Attribute action-xlinkShow_ = attr "xlinkShow"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlinkTitle>-xlinkTitle_ :: MisoString -> Attribute action-xlinkTitle_ = attr "xlinkTitle"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlinkType>-xlinkType_ :: MisoString -> Attribute action-xlinkType_ = attr "xlinkType"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xmlBase>-xmlBase_ :: MisoString -> Attribute action-xmlBase_ = attr "xmlBase"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xmlLang>-xmlLang_ :: MisoString -> Attribute action-xmlLang_ = attr "xmlLang"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xmlSpace>-xmlSpace_ :: MisoString -> Attribute action-xmlSpace_ = attr "xmlSpace"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/y>-y_ :: MisoString -> Attribute action-y_ = attr "y"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/y1>-y1_ :: MisoString -> Attribute action-y1_ = attr "y1"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/y2>-y2_ :: MisoString -> Attribute action-y2_ = attr "y2"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/yChannelSelector>-yChannelSelector_ :: MisoString -> Attribute action-yChannelSelector_ = attr "yChannelSelector"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/z>-z_ :: MisoString -> Attribute action-z_ = attr "z"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/zoomAndPan>-zoomAndPan_ :: MisoString -> Attribute action-zoomAndPan_ = attr "zoomAndPan"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/alignment-baseline>-alignmentBaseline_ :: MisoString -> Attribute action-alignmentBaseline_ = attr "alignment-baseline"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/baseline-shift>-baselineShift_ :: MisoString -> Attribute action-baselineShift_ = attr "baseline-shift"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/clip-path>-clipPath_ :: MisoString -> Attribute action-clipPath_ = attr "clip-path"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/clip-rule>-clipRule_ :: MisoString -> Attribute action-clipRule_ = attr "clip-rule"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/clip>-clip_ :: MisoString -> Attribute action-clip_ = attr "clip"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/color-interpolation-filters>-colorInterpolationFilters_ :: MisoString -> Attribute action-colorInterpolationFilters_ = attr "color-interpolation-filters"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/color-interpolation>-colorInterpolation_ :: MisoString -> Attribute action-colorInterpolation_ = attr "color-interpolation"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/color-profile>-colorProfile_ :: MisoString -> Attribute action-colorProfile_ = attr "color-profile"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/color-rendering>-colorRendering_ :: MisoString -> Attribute action-colorRendering_ = attr "color-rendering"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/color>-color_ :: MisoString -> Attribute action-color_ = attr "color"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/cursor>-cursor_ :: MisoString -> Attribute action-cursor_ = attr "cursor"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/direction>-direction_ :: MisoString -> Attribute action-direction_ = attr "direction"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/display>-display_ :: MisoString -> Attribute action-display_ = attr "display"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/dominant-baseline>-dominantBaseline_ :: MisoString -> Attribute action-dominantBaseline_ = attr "dominant-baseline"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/enable-background>-enableBackground_ :: MisoString -> Attribute action-enableBackground_ = attr "enable-background"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-opacity>-fillOpacity_ :: MisoString -> Attribute action-fillOpacity_ = attr "fill-opacity"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule>-fillRule_ :: MisoString -> Attribute action-fillRule_ = attr "fill-rule"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill>-fill_ :: MisoString -> Attribute action-fill_ = attr "fill"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/filter>-filter_ :: MisoString -> Attribute action-filter_ = attr "filter"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/flood-color>-floodColor_ :: MisoString -> Attribute action-floodColor_ = attr "flood-color"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/flood-opacity>-floodOpacity_ :: MisoString -> Attribute action-floodOpacity_ = attr "flood-opacity"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-family>-fontFamily_ :: MisoString -> Attribute action-fontFamily_ = attr "font-family"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-size-adjust>-fontSizeAdjust_ :: MisoString -> Attribute action-fontSizeAdjust_ = attr "font-size-adjust"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-size>-fontSize_ :: MisoString -> Attribute action-fontSize_ = attr "font-size"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-stretch>-fontStretch_ :: MisoString -> Attribute action-fontStretch_ = attr "font-stretch"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-style>-fontStyle_ :: MisoString -> Attribute action-fontStyle_ = attr "font-style"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-variant>-fontVariant_ :: MisoString -> Attribute action-fontVariant_ = attr "font-variant"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/font-weight>-fontWeight_ :: MisoString -> Attribute action-fontWeight_ = attr "font-weight"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/glyph-orientation-horizontal>-glyphOrientationHorizontal_ :: MisoString -> Attribute action-glyphOrientationHorizontal_ = attr "glyph-orientation-horizontal"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/glyph-orientation-vertical>-glyphOrientationVertical_ :: MisoString -> Attribute action-glyphOrientationVertical_ = attr "glyph-orientation-vertical"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/image-rendering>-imageRendering_ :: MisoString -> Attribute action-imageRendering_ = attr "image-rendering"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/kerning>-kerning_ :: MisoString -> Attribute action-kerning_ = attr "kerning"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/letter-spacing>-letterSpacing_ :: MisoString -> Attribute action-letterSpacing_ = attr "letter-spacing"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/lighting-color>-lightingColor_ :: MisoString -> Attribute action-lightingColor_ = attr "lighting-color"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/marker-end>-markerEnd_ :: MisoString -> Attribute action-markerEnd_ = attr "marker-end"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/marker-mid>-markerMid_ :: MisoString -> Attribute action-markerMid_ = attr "marker-mid"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/marker-start>-markerStart_ :: MisoString -> Attribute action-markerStart_ = attr "marker-start"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/mask>-mask_ :: MisoString -> Attribute action-mask_ = attr "mask"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/opacity>-opacity_ :: MisoString -> Attribute action-opacity_ = attr "opacity"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/overflow>-overflow_ :: MisoString -> Attribute action-overflow_ = attr "overflow"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointer-events>-pointerEvents_ :: MisoString -> Attribute action-pointerEvents_ = attr "pointer-events"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering>-shapeRendering_ :: MisoString -> Attribute action-shapeRendering_ = attr "shape-rendering"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stop-color>-stopColor_ :: MisoString -> Attribute action-stopColor_ = attr "stop-color"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stop-opacity>-stopOpacity_ :: MisoString -> Attribute action-stopOpacity_ = attr "stop-opacity"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray>-strokeDasharray_ :: MisoString -> Attribute action-strokeDasharray_ = attr "stroke-dasharray"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dashoffset>-strokeDashoffset_ :: MisoString -> Attribute action-strokeDashoffset_ = attr "stroke-dashoffset"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linecap>-strokeLinecap_ :: MisoString -> Attribute action-strokeLinecap_ = attr "stroke-linecap"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linejoin>-strokeLinejoin_ :: MisoString -> Attribute action-strokeLinejoin_ = attr "stroke-linejoin"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit>-strokeMiterlimit_ :: MisoString -> Attribute action-strokeMiterlimit_ = attr "stroke-miterlimit"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-opacity>-strokeOpacity_ :: MisoString -> Attribute action-strokeOpacity_ = attr "stroke-opacity"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-width>-strokeWidth_ :: MisoString -> Attribute action-strokeWidth_ = attr "stroke-width"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke>-stroke_ :: MisoString -> Attribute action-stroke_ = attr "stroke"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor>-textAnchor_ :: MisoString -> Attribute action-textAnchor_ = attr "text-anchor"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-decoration>-textDecoration_ :: MisoString -> Attribute action-textDecoration_ = attr "text-decoration"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-rendering>-textRendering_ :: MisoString -> Attribute action-textRendering_ = attr "text-rendering"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/unicode-bidi>-unicodeBidi_ :: MisoString -> Attribute action-unicodeBidi_ = attr "unicode-bidi"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/visibility>-visibility_ :: MisoString -> Attribute action-visibility_ = attr "visibility"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/word-spacing>-wordSpacing_ :: MisoString -> Attribute action-wordSpacing_ = attr "word-spacing"--- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/writing-mode>-writingMode_ :: MisoString -> Attribute action-writingMode_ = attr "writing-mode"
src/Miso/Svg/Element.hs view
@@ -1,19 +1,18 @@+----------------------------------------------------------------------------- {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE NoImplicitPrelude #-} ----------------------------------------------------------------------------- -- | -- Module : Miso.Svg.Element--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable ---------------------------------------------------------------------------- module Miso.Svg.Element- ( -- * HTML Embedding+ ( -- *** SVG svg_- , foreignObject_- -- * Graphics Elements+ -- *** Graphics , circle_ , ellipse_ , image_@@ -23,51 +22,33 @@ , polyline_ , rect_ , use_- -- * Animation Elements+ -- *** Animation , animate_- , animateColor_ , animateMotion_ , animateTransform_ , mpath_ , set_- -- * Descriptive Elements+ -- *** Descriptive , desc_ , metadata_ , title_- -- * Containers- , a_+ -- *** Containers , defs_ , g_ , marker_ , mask_- , missingGlyph_ , pattern_ , switch_ , symbol_- -- * Text- , altGlyph_- , altGlyphDef_- , altGlyphItem_- , glyph_- , glyphRef_+ -- *** Text , textPath_ , text_- , tref_ , tspan_- -- * Fonts- , font_- , fontFace_- , fontFaceFormat_- , fontFaceName_- , fontFaceSrc_- , fontFaceUri_- , hkern_- , vkern_- -- * Gradients+ -- *** Gradients , linearGradient_ , radialGradient_ , stop_- -- * Filters+ -- *** Filters , feBlend_ , feColorMatrix_ , feComponentTransfer_@@ -75,6 +56,7 @@ , feConvolveMatrix_ , feDiffuseLighting_ , feDisplacementMap_+ , feDropShadow_ , feFlood_ , feFuncA_ , feFuncB_@@ -84,352 +66,282 @@ , feImage_ , feMerge_ , feMergeNode_- , feMorhpology_+ , feMorphology_ , feOffset_ , feSpecularLighting_ , feTile_ , feTurbulence_- -- * Light source elements+ -- *** Light source , feDistantLight_ , fePointLight_ , feSpotLight_- -- * Miscellaneous+ -- *** Misc.+ , foreignObject_ , clipPath_- , colorProfile_- , cursor_ , filter_ , script_ , style_ , view_ ) where--import Miso.Html.Types hiding (style_)-import Miso.String (MisoString)-import qualified Prelude as P---- | Used to construct a `VNode` with namespace "svg"+-----------------------------------------------------------------------------+import Miso.Types hiding (text_)+-----------------------------------------------------------------------------+-- | Used to construct a @VNode@ with namespace *"svg"* -- -- > document.createElementNS('http://www.w3.org/2000/svg', 'circle'); ---nodeSvg_ :: MisoString -> [Attribute action] -> [View action] -> View action-nodeSvg_ = P.flip (node SVG) P.Nothing---- | Creates an svg tag-svg_ :: [Attribute action] -> [View action] -> View action-svg_ = nodeSvg_ "svg"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject>-foreignObject_ :: [Attribute action] -> [View action] -> View action-foreignObject_ = nodeSvg_ "foreignObject"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/circle>-circle_ :: [Attribute action] -> [View action] -> View action-circle_ = nodeSvg_ "circle"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/ellipse>-ellipse_ :: [Attribute action] -> [View action] -> View action-ellipse_ = nodeSvg_ "ellipse"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image>-image_ :: [Attribute action] -> [View action] -> View action-image_ = nodeSvg_ "image"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/line>-line_ :: [Attribute action] -> [View action] -> View action-line_ = nodeSvg_ "line"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path>-path_ :: [Attribute action] -> [View action] -> View action-path_ = nodeSvg_ "path"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/polygon>-polygon_ :: [Attribute action] -> [View action] -> View action-polygon_ = nodeSvg_ "polygon"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/polyline>-polyline_ :: [Attribute action] -> [View action] -> View action-polyline_ = nodeSvg_ "polyline"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/rect>-rect_ :: [Attribute action] -> [View action] -> View action-rect_ = nodeSvg_ "rect"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use>-use_ :: [Attribute action] -> [View action] -> View action-use_ = nodeSvg_ "use"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/animate>-animate_ :: [Attribute action] -> [View action] -> View action-animate_ = nodeSvg_ "animate"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/animateColor>-animateColor_ :: [Attribute action] -> [View action] -> View action-animateColor_ = nodeSvg_ "animateColor"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/animateMotion>-animateMotion_ :: [Attribute action] -> [View action] -> View action-animateMotion_ = nodeSvg_ "animateMotion"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/animateTransform>-animateTransform_ :: [Attribute action] -> [View action] -> View action-animateTransform_ = nodeSvg_ "animateTransform"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/mpath>-mpath_ :: [Attribute action] -> [View action] -> View action-mpath_ = nodeSvg_ "mpath"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/set>-set_ :: [Attribute action] -> [View action] -> View action-set_ = nodeSvg_ "set"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/desc>-desc_ :: [Attribute action] -> [View action] -> View action-desc_ = nodeSvg_ "desc"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/metadata>-metadata_ :: [Attribute action] -> [View action] -> View action-metadata_ = nodeSvg_ "metadata"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/title>-title_ :: [Attribute action] -> [View action] -> View action-title_ = nodeSvg_ "title"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/a>-a_ :: [Attribute action] -> [View action] -> View action-a_ = nodeSvg_ "a"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs>-defs_ :: [Attribute action] -> [View action] -> View action-defs_ = nodeSvg_ "defs"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g>-g_ :: [Attribute action] -> [View action] -> View action-g_ = nodeSvg_ "g"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/marker>-marker_ :: [Attribute action] -> [View action] -> View action-marker_ = nodeSvg_ "marker"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/mask>-mask_ :: [Attribute action] -> [View action] -> View action-mask_ = nodeSvg_ "mask"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/missingGlyph>-missingGlyph_ :: [Attribute action] -> [View action] -> View action-missingGlyph_ = nodeSvg_ "missingGlyph"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/pattern>-pattern_ :: [Attribute action] -> [View action] -> View action-pattern_ = nodeSvg_ "pattern"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/switch>-switch_ :: [Attribute action] -> [View action] -> View action-switch_ = nodeSvg_ "switch"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/symbol>-symbol_ :: [Attribute action] -> [View action] -> View action-symbol_ = nodeSvg_ "symbol"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/altGlyph>-altGlyph_ :: [Attribute action] -> [View action] -> View action-altGlyph_ = nodeSvg_ "altGlyph"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/altGlyphDef>-altGlyphDef_ :: [Attribute action] -> [View action] -> View action-altGlyphDef_ = nodeSvg_ "altGlyphDef"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/altGlyphItem>-altGlyphItem_ :: [Attribute action] -> [View action] -> View action-altGlyphItem_ = nodeSvg_ "altGlyphItem"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/glyph>-glyph_ :: [Attribute action] -> [View action] -> View action-glyph_ = nodeSvg_ "glyph"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/glyphRef>-glyphRef_ :: [Attribute action] -> [View action] -> View action-glyphRef_ = nodeSvg_ "glyphRef"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/textPath>-textPath_ :: [Attribute action] -> [View action] -> View action-textPath_ = nodeSvg_ "textPath"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/text>-text_ :: [Attribute action] -> [View action] -> View action-text_ = nodeSvg_ "text"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/tref>-tref_ :: [Attribute action] -> [View action] -> View action-tref_ = nodeSvg_ "tref"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/tspan>-tspan_ :: [Attribute action] -> [View action] -> View action-tspan_ = nodeSvg_ "tspan"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/font>-font_ :: [Attribute action] -> [View action] -> View action-font_ = nodeSvg_ "font"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/font-face>-fontFace_ :: [Attribute action] -> [View action] -> View action-fontFace_ = nodeSvg_ "font-face"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/font-face-format>-fontFaceFormat_ :: [Attribute action] -> [View action] -> View action-fontFaceFormat_ = nodeSvg_ "font-face-format"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/font-face-name>-fontFaceName_ :: [Attribute action] -> [View action] -> View action-fontFaceName_ = nodeSvg_ "font-face-name"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/font-face-src>-fontFaceSrc_ :: [Attribute action] -> [View action] -> View action-fontFaceSrc_ = nodeSvg_ "font-face-src"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/font-face-uri>-fontFaceUri_ :: [Attribute action] -> [View action] -> View action-fontFaceUri_ = nodeSvg_ "font-face-uri"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/hkern>-hkern_ :: [Attribute action] -> [View action] -> View action-hkern_ = nodeSvg_ "hkern"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/vkern>-vkern_ :: [Attribute action] -> [View action] -> View action-vkern_ = nodeSvg_ "vkern"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient>-linearGradient_ :: [Attribute action] -> [View action] -> View action-linearGradient_ = nodeSvg_ "linearGradient"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/radialGradient>-radialGradient_ :: [Attribute action] -> [View action] -> View action-radialGradient_ = nodeSvg_ "radialGradient"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/stop>-stop_ :: [Attribute action] -> [View action] -> View action-stop_ = nodeSvg_ "stop"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feBlend>-feBlend_ :: [Attribute action] -> [View action] -> View action-feBlend_ = nodeSvg_ "feBlend"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feColorMatrix>-feColorMatrix_ :: [Attribute action] -> [View action] -> View action-feColorMatrix_ = nodeSvg_ "feColorMatrix"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feComponentTransfer>-feComponentTransfer_ :: [Attribute action] -> [View action] -> View action-feComponentTransfer_ = nodeSvg_ "feComponentTransfer"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feComposite>-feComposite_ :: [Attribute action] -> [View action] -> View action-feComposite_ = nodeSvg_ "feComposite"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feConvolveMatrix>-feConvolveMatrix_ :: [Attribute action] -> [View action] -> View action-feConvolveMatrix_ = nodeSvg_ "feConvolveMatrix"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feDiffuseLighting>-feDiffuseLighting_ :: [Attribute action] -> [View action] -> View action-feDiffuseLighting_ = nodeSvg_ "feDiffuseLighting"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feDisplacementMap>-feDisplacementMap_ :: [Attribute action] -> [View action] -> View action-feDisplacementMap_ = nodeSvg_ "feDisplacementMap"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFlood>-feFlood_ :: [Attribute action] -> [View action] -> View action-feFlood_ = nodeSvg_ "feFlood"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFuncA>-feFuncA_ :: [Attribute action] -> [View action] -> View action-feFuncA_ = nodeSvg_ "feFuncA"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFuncB>-feFuncB_ :: [Attribute action] -> [View action] -> View action-feFuncB_ = nodeSvg_ "feFuncB"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFuncG>-feFuncG_ :: [Attribute action] -> [View action] -> View action-feFuncG_ = nodeSvg_ "feFuncG"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feFuncR>-feFuncR_ :: [Attribute action] -> [View action] -> View action-feFuncR_ = nodeSvg_ "feFuncR"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feGaussianBlur>-feGaussianBlur_ :: [Attribute action] -> [View action] -> View action-feGaussianBlur_ = nodeSvg_ "feGaussianBlur"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feImage>-feImage_ :: [Attribute action] -> [View action] -> View action-feImage_ = nodeSvg_ "feImage"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feMerge>-feMerge_ :: [Attribute action] -> [View action] -> View action-feMerge_ = nodeSvg_ "feMerge"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feMergeNode>-feMergeNode_ :: [Attribute action] -> [View action] -> View action-feMergeNode_ = nodeSvg_ "feMergeNode"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feMorhpology>-feMorhpology_ :: [Attribute action] -> [View action] -> View action-feMorhpology_ = nodeSvg_ "feMorhpology"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feOffset>-feOffset_ :: [Attribute action] -> [View action] -> View action-feOffset_ = nodeSvg_ "feOffset"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feSpecularLighting>-feSpecularLighting_ :: [Attribute action] -> [View action] -> View action-feSpecularLighting_ = nodeSvg_ "feSpecularLighting"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feTile>-feTile_ :: [Attribute action] -> [View action] -> View action-feTile_ = nodeSvg_ "feTile"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feTurbulence>-feTurbulence_ :: [Attribute action] -> [View action] -> View action-feTurbulence_ = nodeSvg_ "feTurbulence"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feDistantLight>-feDistantLight_ :: [Attribute action] -> [View action] -> View action-feDistantLight_ = nodeSvg_ "feDistantLight"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/fePointLight>-fePointLight_ :: [Attribute action] -> [View action] -> View action-fePointLight_ = nodeSvg_ "fePointLight"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feSpotLight>-feSpotLight_ :: [Attribute action] -> [View action] -> View action-feSpotLight_ = nodeSvg_ "feSpotLight"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/clipPath>-clipPath_ :: [Attribute action] -> [View action] -> View action-clipPath_ = nodeSvg_ "clipPath"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/color-profile>-colorProfile_ :: [Attribute action] -> [View action] -> View action-colorProfile_ = nodeSvg_ "color-profile"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/cursor>-cursor_ :: [Attribute action] -> [View action] -> View action-cursor_ = nodeSvg_ "cursor"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/filter>-filter_ :: [Attribute action] -> [View action] -> View action-filter_ = nodeSvg_ "filter"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/script>-script_ :: [Attribute action] -> [View action] -> View action-script_ = nodeSvg_ "script"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/style>-style_ :: [Attribute action] -> [View action] -> View action-style_ = nodeSvg_ "style"---- | <https://developer.mozilla.org/en-US/docs/Web/SVG/Element/view>-view_ :: [Attribute action] -> [View action] -> View action-view_ = nodeSvg_ "view"+nodeSvg :: MisoString -> [Attribute action] -> [View model action] -> View model action+nodeSvg nodeName = node SVG nodeName+-----------------------------------------------------------------------------+-- | [\<svg\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/svg)+svg_ :: [Attribute action] -> [View model action] -> View model action+svg_ = nodeSvg "svg"+-----------------------------------------------------------------------------+-- | [\<foreignObject\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/foreignObject)+foreignObject_ :: [Attribute action] -> [View model action] -> View model action+foreignObject_ = nodeSvg "foreignObject"+-----------------------------------------------------------------------------+-- | [\<circle\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/circle)+circle_ :: [Attribute action] -> View model action+circle_ = flip (nodeSvg "circle") []+-----------------------------------------------------------------------------+-- | [\<ellipse\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/ellipse)+ellipse_ :: [Attribute action] -> View model action+ellipse_ = flip (nodeSvg "ellipse") []+-----------------------------------------------------------------------------+-- | [\<image\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/image)+image_ :: [Attribute action] -> View model action+image_ = flip (nodeSvg "image") []+-----------------------------------------------------------------------------+-- | [\<line\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/line)+line_ :: [Attribute action] -> View model action+line_ = flip (nodeSvg "line") []+-----------------------------------------------------------------------------+-- | [\<path\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/path)+path_ :: [Attribute action] -> View model action+path_ = flip (nodeSvg "path") []+-----------------------------------------------------------------------------+-- | [\<polygon\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/polygon)+polygon_ :: [Attribute action] -> View model action+polygon_ = flip (nodeSvg "polygon") []+-----------------------------------------------------------------------------+-- | [\<polyline\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/polyline)+polyline_ :: [Attribute action] -> View model action+polyline_ = flip (nodeSvg "polyline") []+-----------------------------------------------------------------------------+-- | [\<rect\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/rect)+rect_ :: [Attribute action] -> View model action+rect_ = flip (nodeSvg "rect") []+-----------------------------------------------------------------------------+-- | [\<use\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/use)+use_ :: [Attribute action] -> View model action+use_ = flip (nodeSvg "use") []+-----------------------------------------------------------------------------+-- | [\<animate\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/animate)+animate_ :: [Attribute action] -> View model action+animate_ = flip (nodeSvg "animate") []+-----------------------------------------------------------------------------+-- | [\<animateMotion\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/animateMotion)+animateMotion_ :: [Attribute action] -> View model action+animateMotion_ = flip (nodeSvg "animateMotion") []+-----------------------------------------------------------------------------+-- | [\<animateTransform\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/animateTransform)+animateTransform_ :: [Attribute action] -> View model action+animateTransform_ = flip (nodeSvg "animateTransform") []+-----------------------------------------------------------------------------+-- | [\<mpath\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/mpath)+mpath_ :: [Attribute action] -> View model action+mpath_ = flip (nodeSvg "mpath") []+-----------------------------------------------------------------------------+-- | [\<set\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/set)+set_ :: [Attribute action] -> View model action+set_ = flip (nodeSvg "set") []+-----------------------------------------------------------------------------+-- | [\<desc\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/desc)+desc_ :: [Attribute action] -> [View model action] -> View model action+desc_ = nodeSvg "desc"+-----------------------------------------------------------------------------+-- | [\<metadata\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/metadata)+metadata_ :: [Attribute action] -> [View model action] -> View model action+metadata_ = nodeSvg "metadata"+-----------------------------------------------------------------------------+-- | [\<title\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/title)+title_ :: [Attribute action] -> [View model action] -> View model action+title_ = nodeSvg "title"+-----------------------------------------------------------------------------+-- | [\<defs\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/defs)+defs_ :: [Attribute action] -> [View model action] -> View model action+defs_ = nodeSvg "defs"+-----------------------------------------------------------------------------+-- | [\<g\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/g)+g_ :: [Attribute action] -> [View model action] -> View model action+g_ = nodeSvg "g"+-----------------------------------------------------------------------------+-- | [\<marker\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/marker)+marker_ :: [Attribute action] -> [View model action] -> View model action+marker_ = nodeSvg "marker"+-----------------------------------------------------------------------------+-- | [\<mask\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/mask)+mask_ :: [Attribute action] -> [View model action] -> View model action+mask_ = nodeSvg "mask"+-----------------------------------------------------------------------------+-- | [\<pattern\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/pattern)+pattern_ :: [Attribute action] -> [View model action] -> View model action+pattern_ = nodeSvg "pattern"+-----------------------------------------------------------------------------+-- | [\<switch\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/switch)+switch_ :: [Attribute action] -> [View model action] -> View model action+switch_ = nodeSvg "switch"+-----------------------------------------------------------------------------+-- | [\<symbol\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/symbol)+symbol_ :: [Attribute action] -> [View model action] -> View model action+symbol_ = nodeSvg "symbol"+-----------------------------------------------------------------------------+-- | [\<textPath\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/textPath)+textPath_ :: [Attribute action] -> [View model action] -> View model action+textPath_ = nodeSvg "textPath"+-----------------------------------------------------------------------------+-- | [\<text\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/text)+text_ :: [Attribute action] -> [View model action] -> View model action+text_ = nodeSvg "text"+-----------------------------------------------------------------------------+-- | [\<tspan\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/tspan)+tspan_ :: [Attribute action] -> [View model action] -> View model action+tspan_ = nodeSvg "tspan"+-----------------------------------------------------------------------------+-- | [\<linearGradient\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/linearGradient)+linearGradient_ :: [Attribute action] -> [View model action] -> View model action+linearGradient_ = nodeSvg "linearGradient"+-----------------------------------------------------------------------------+-- | [\<radialGradient\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/radialGradient)+radialGradient_ :: [Attribute action] -> [View model action] -> View model action+radialGradient_ = nodeSvg "radialGradient"+-----------------------------------------------------------------------------+-- | [\<stop\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/stop)+stop_ :: [Attribute action] -> View model action+stop_ = flip (nodeSvg "stop") []+-----------------------------------------------------------------------------+-- | [\<feBlend\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feBlend)+feBlend_ :: [Attribute action] -> View model action+feBlend_ = flip (nodeSvg "feBlend") []+-----------------------------------------------------------------------------+-- | [\<feColorMatrix\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feColorMatrix)+feColorMatrix_ :: [Attribute action] -> View model action+feColorMatrix_ = flip (nodeSvg "feColorMatrix") []+-----------------------------------------------------------------------------+-- | [\<feComponentTransfer\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feComponentTransfer)+feComponentTransfer_ :: [Attribute action] -> [View model action] -> View model action+feComponentTransfer_ = nodeSvg "feComponentTransfer"+-----------------------------------------------------------------------------+-- | [\<feComposite\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feComposite)+feComposite_ :: [Attribute action] -> View model action+feComposite_ = flip (nodeSvg "feComposite") []+-----------------------------------------------------------------------------+-- | [\<feConvolveMatrix\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feConvolveMatrix)+feConvolveMatrix_ :: [Attribute action] -> View model action+feConvolveMatrix_ = flip (nodeSvg "feConvolveMatrix") []+-----------------------------------------------------------------------------+-- | [\<feDiffuseLighting\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feDiffuseLighting)+feDiffuseLighting_ :: [Attribute action] -> [View model action] -> View model action+feDiffuseLighting_ = nodeSvg "feDiffuseLighting"+-----------------------------------------------------------------------------+-- | [\<feDisplacementMap\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feDisplacementMap)+feDisplacementMap_ :: [Attribute action] -> View model action+feDisplacementMap_ = flip (nodeSvg "feDisplacementMap") []+-----------------------------------------------------------------------------+-- | [\<feDropShadow\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feDropShadow)+--+-- @since 1.9.0.0+feDropShadow_ :: [Attribute action] -> View model action+feDropShadow_ = flip (nodeSvg "feDropShadow") []+-----------------------------------------------------------------------------+-- | [\<feFlood\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feFlood)+feFlood_ :: [Attribute action] -> View model action+feFlood_ = flip (nodeSvg "feFlood") []+-----------------------------------------------------------------------------+-- | [\<feFuncA\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feFuncA)+feFuncA_ :: [Attribute action] -> [View model action] -> View model action+feFuncA_ = nodeSvg "feFuncA"+-----------------------------------------------------------------------------+-- | [\<feFuncB\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feFuncB)+feFuncB_ :: [Attribute action] -> [View model action] -> View model action+feFuncB_ = nodeSvg "feFuncB"+-----------------------------------------------------------------------------+-- | [\<feFuncG\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feFuncG)+feFuncG_ :: [Attribute action] -> [View model action] -> View model action+feFuncG_ = nodeSvg "feFuncG"+-----------------------------------------------------------------------------+-- | [\<feFuncR\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feFuncR)+feFuncR_ :: [Attribute action] -> [View model action] -> View model action+feFuncR_ = nodeSvg "feFuncR"+-----------------------------------------------------------------------------+-- | [\<feGaussianBlur\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feGaussianBlur)+feGaussianBlur_ :: [Attribute action] -> View model action+feGaussianBlur_ = flip (nodeSvg "feGaussianBlur") []+-----------------------------------------------------------------------------+-- | [\<feImage\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feImage)+feImage_ :: [Attribute action] -> View model action+feImage_ = flip (nodeSvg "feImage") []+-----------------------------------------------------------------------------+-- | [\<feMerge\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feMerge)+feMerge_ :: [Attribute action] -> [View model action] -> View model action+feMerge_ = nodeSvg "feMerge"+-----------------------------------------------------------------------------+-- | [\<feMergeNode\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feMergeNode)+feMergeNode_ :: [Attribute action] -> View model action+feMergeNode_ = flip (nodeSvg "feMergeNode") []+-----------------------------------------------------------------------------+-- | [\<feMorphology\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feMorphology)+--+-- @since 1.9.0.0+feMorphology_ :: [Attribute action] -> View model action+feMorphology_ = flip (nodeSvg "feMorphology") []+-----------------------------------------------------------------------------+-- | [\<feOffset\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feOffset)+feOffset_ :: [Attribute action] -> View model action+feOffset_ = flip (nodeSvg "feOffset") []+-----------------------------------------------------------------------------+-- | [\<feSpecularLighting\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feSpecularLighting)+feSpecularLighting_ :: [Attribute action] -> [View model action] -> View model action+feSpecularLighting_ = nodeSvg "feSpecularLighting"+-----------------------------------------------------------------------------+-- | [\<feTile\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feTile)+feTile_ :: [Attribute action] -> View model action+feTile_ = flip (nodeSvg "feTile") []+-----------------------------------------------------------------------------+-- | [\<feTurbulence\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feTurbulence)+feTurbulence_ :: [Attribute action] -> View model action+feTurbulence_ = flip (nodeSvg "feTurbulence") []+-----------------------------------------------------------------------------+-- | [\<feDistantLight\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feDistantLight)+feDistantLight_ :: [Attribute action] -> [View model action] -> View model action+feDistantLight_ = nodeSvg "feDistantLight"+-----------------------------------------------------------------------------+-- | [\<fePointLight\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/fePointLight)+fePointLight_ :: [Attribute action] -> View model action+fePointLight_ = flip (nodeSvg "fePointLight") []+-----------------------------------------------------------------------------+-- | [\<feSpotLight\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/feSpotLight)+feSpotLight_ :: [Attribute action] -> View model action+feSpotLight_ = flip (nodeSvg "feSpotLight") []+-----------------------------------------------------------------------------+-- | [\<clipPath\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/clipPath)+clipPath_ :: [Attribute action] -> [View model action] -> View model action+clipPath_ = nodeSvg "clipPath"+-----------------------------------------------------------------------------+-- | [\<filter\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/filter)+filter_ :: [Attribute action] -> [View model action] -> View model action+filter_ = nodeSvg "filter"+-----------------------------------------------------------------------------+-- | [\<script\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/script)+script_ :: [Attribute action] -> [View model action] -> View model action+script_ = nodeSvg "script"+-----------------------------------------------------------------------------+-- | [\<style\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/style)+style_ :: [Attribute action] -> [View model action] -> View model action+style_ = nodeSvg "style"+-----------------------------------------------------------------------------+-- | [\<view\>](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/view)+view_ :: [Attribute action] -> View model action+view_ = flip (nodeSvg "view") []+-----------------------------------------------------------------------------
src/Miso/Svg/Event.hs view
@@ -1,3 +1,4 @@+----------------------------------------------------------------------------- {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE DataKinds #-}@@ -6,26 +7,24 @@ ----------------------------------------------------------------------------- -- | -- Module : Miso.Svg.Events--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable ---------------------------------------------------------------------------- module Miso.Svg.Event- ( -- * Animation event handlers+ ( -- *** Animation onBegin , onEnd , onRepeat- -- * Document event attributes+ -- *** Document , onAbort , onError , onResize , onScroll- , onLoad- , onUnload , onZoom- -- * Graphical Event Attributes+ -- *** Graphical , onActivate , onClick , onFocusIn@@ -36,81 +35,72 @@ , onMouseOver , onMouseUp ) where--import Miso.Event +-----------------------------------------------------------------------------+import Miso.Event (on, emptyDecoder) import Miso.Html.Event (onClick)-import Miso.Html.Types-+import Miso.Types (Attribute)+----------------------------------------------------------------------------- -- | onBegin event onBegin :: action -> Attribute action-onBegin action = on "begin" emptyDecoder $ \() -> action-+onBegin action = on "begin" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onEnd event onEnd :: action -> Attribute action-onEnd action = on "end" emptyDecoder $ \() -> action-+onEnd action = on "end" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onRepeat event onRepeat :: action -> Attribute action-onRepeat action = on "repeat" emptyDecoder $ \() -> action-+onRepeat action = on "repeat" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onAbort event onAbort :: action -> Attribute action-onAbort action = on "abort" emptyDecoder $ \() -> action-+onAbort action = on "abort" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onError event onError :: action -> Attribute action-onError action = on "error" emptyDecoder $ \() -> action-+onError action = on "error" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onResize event onResize :: action -> Attribute action-onResize action = on "resize" emptyDecoder $ \() -> action-+onResize action = on "resize" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onScroll event onScroll :: action -> Attribute action-onScroll action = on "scroll" emptyDecoder $ \() -> action---- | onLoad event-onLoad :: action -> Attribute action-onLoad action = on "load" emptyDecoder $ \() -> action---- | onUnload event-onUnload :: action -> Attribute action-onUnload action = on "unload" emptyDecoder $ \() -> action-+onScroll action = on "scroll" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onZoom event onZoom :: action -> Attribute action-onZoom action = on "zoom" emptyDecoder $ \() -> action-+onZoom action = on "zoom" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onActivate event onActivate :: action -> Attribute action-onActivate action = on "activate" emptyDecoder $ \() -> action-+onActivate action = on "activate" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onFocusIn event onFocusIn :: action -> Attribute action-onFocusIn action = on "focusin" emptyDecoder $ \() -> action-+onFocusIn action = on "focusin" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onFocusOut event onFocusOut :: action -> Attribute action-onFocusOut action = on "focusout" emptyDecoder $ \() -> action-+onFocusOut action = on "focusout" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onMouseDown event onMouseDown :: action -> Attribute action-onMouseDown action = on "mousedown" emptyDecoder $ \() -> action+onMouseDown action = on "mousedown" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onMouseMove event onMouseMove :: action -> Attribute action-onMouseMove action = on "mousemove" emptyDecoder $ \() -> action-+onMouseMove action = on "mousemove" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onMouseOut event onMouseOut :: action -> Attribute action-onMouseOut action = on "mouseout" emptyDecoder $ \() -> action-+onMouseOut action = on "mouseout" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onMouseOver event onMouseOver :: action -> Attribute action-onMouseOver action = on "mouseover" emptyDecoder $ \() -> action-+onMouseOver action = on "mouseover" emptyDecoder $ \() _ -> action+----------------------------------------------------------------------------- -- | onMouseUp event onMouseUp :: action -> Attribute action-onMouseUp action = on "mouseup" emptyDecoder $ \() -> action---+onMouseUp action = on "mouseup" emptyDecoder $ \() _ -> action+-----------------------------------------------------------------------------
+ src/Miso/Svg/Property.hs view
@@ -0,0 +1,887 @@+-----------------------------------------------------------------------------+{-# LANGUAGE OverloadedStrings #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Svg.Property+-- Copyright : (C) 2016-2026 David M. Johnson+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+--+-- <https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute>+--+----------------------------------------------------------------------------+module Miso.Svg.Property+ ( -- *** Regular Attributes+ accumulate_+ , additive_+ , amplitude_+ , attributeName_+ , azimuth_+ , baseFrequency_+ , begin_+ , bias_+ , by_+ , calcMode_+ , clipPathUnits_+ , cx_+ , cy_+ , d_+ , decoding_+ , diffuseConstant_+ , divisor_+ , dur_+ , dx_+ , dy_+ , edgeMode_+ , elevation_+ , end_+ , exponent_+ , filterUnits_+ , fr_+ , from_+ , fx_+ , fy_+ , gradientTransform_+ , gradientUnits_+ , in_'+ , in2_+ , intercept_+ , k1_+ , k2_+ , k3_+ , k4_+ , kernelMatrix_+ , keyPoints_+ , keySplines_+ , keyTimes_+ , lengthAdjust_+ , limitingConeAngle_+ , markerHeight_+ , markerUnits_+ , markerWidth_+ , maskContentUnits_+ , maskUnits_+ , max_+ , media_+ , method_+ , min_+ , mode_+ , numOctaves_+ , operator_+ , order_+ , orient_+ , origin_+ , paintOrder_+ , path_+ , pathLength_+ , patternContentUnits_+ , patternTransform_+ , patternUnits_+ , points_+ , pointsAtX_+ , pointsAtY_+ , pointsAtZ_+ , preserveAlpha_+ , preserveAspectRatio_+ , primitiveUnits_+ , r_+ , radius_+ , refX_+ , refY_+ , repeatCount_+ , repeatDur_+ , restart_+ , result_+ , rotate_+ , rx_+ , ry_+ , scale_+ , seed_+ , side_+ , slope_+ , spacing_+ , specularConstant_+ , specularExponent_+ , spreadMethod_+ , startOffset_+ , stdDeviation_+ , stitchTiles_+ , surfaceScale_+ , systemLanguage_+ , tableValues_+ , target_+ , targetX_+ , targetY_+ , textLength_+ , to_+ , transform_+ , transformOrigin_+ , type_'+ , values_+ , vectorEffect_+ , viewBox_+ , x_+ , x1_+ , x2_+ , xChannelSelector_+ , y_+ , y1_+ , y2_+ , yChannelSelector_+ , z_+ -- *** Presentation attributes+ --+ -- | All SVG presentation attributes can be used as CSS properties.+ , alignmentBaseline_+ , baselineShift_+ , clipPath_+ , clipRule_+ , color_+ , colorInterpolation_+ , colorInterpolationFilters_+ , crossorigin_+ , cursor_+ , direction_+ , display_+ , dominantBaseline_+ , fill_+ , fillOpacity_+ , fillRule_+ , filter_+ , floodColor_+ , floodOpacity_+ , fontFamily_+ , fontSize_+ , fontSizeAdjust_+ , fontStyle_+ , fontVariant_+ , fontWeight_+ , imageRendering_+ , letterSpacing_+ , lightingColor_+ , markerEnd_+ , markerMid_+ , markerStart_+ , mask_+ , opacity_+ , overflow_+ , pointerEvents_+ , shapeRendering_+ , stopColor_+ , stopOpacity_+ , stroke_+ , strokeDasharray_+ , strokeDashoffset_+ , strokeLinecap_+ , strokeLinejoin_+ , strokeMiterlimit_+ , strokeOpacity_+ , strokeWidth_+ , textAnchor_+ , textDecoration_+ , textRendering_+ , unicodeBidi_+ , visibility_+ , wordSpacing_+ , writingMode_+ ) where+-----------------------------------------------------------------------------+import Miso.Property ( textProp )+import Miso.String ( MisoString )+import Miso.Types ( Attribute )+-----------------------------------------------------------------------------+attr :: MisoString -> MisoString -> Attribute action+attr = textProp+-----------------------------------------------------------------------------+-- | [accumulate](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/accumulate) attribute+accumulate_ :: MisoString -> Attribute action+accumulate_ = attr "accumulate"+-----------------------------------------------------------------------------+-- | [additive](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/additive) attribute+additive_ :: MisoString -> Attribute action+additive_ = attr "additive"+-----------------------------------------------------------------------------+-- | [amplitude](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/amplitude) attribute+amplitude_ :: MisoString -> Attribute action+amplitude_ = attr "amplitude"+-----------------------------------------------------------------------------+-- | [attributeName](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/attributeName) attribute+attributeName_ :: MisoString -> Attribute action+attributeName_ = attr "attributeName"+-----------------------------------------------------------------------------+-- | [azimuth](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/azimuth) attribute+azimuth_ :: MisoString -> Attribute action+azimuth_ = attr "azimuth"+-----------------------------------------------------------------------------+-- | [baseFrequency](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/baseFrequency) attribute+baseFrequency_ :: MisoString -> Attribute action+baseFrequency_ = attr "baseFrequency"+-----------------------------------------------------------------------------+-- | [begin](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/begin) attribute+begin_ :: MisoString -> Attribute action+begin_ = attr "begin"+-----------------------------------------------------------------------------+-- | [bias](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/bias) attribute+bias_ :: MisoString -> Attribute action+bias_ = attr "bias"+-----------------------------------------------------------------------------+-- | [by](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/by) attribute+by_ :: MisoString -> Attribute action+by_ = attr "by"+-----------------------------------------------------------------------------+-- | [calcMode](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/calcMode) attribute+calcMode_ :: MisoString -> Attribute action+calcMode_ = attr "calcMode"+-----------------------------------------------------------------------------+-- | [clipPathUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/clipPathUnits) attribute+clipPathUnits_ :: MisoString -> Attribute action+clipPathUnits_ = attr "clipPathUnits"+-----------------------------------------------------------------------------+-- | [cx](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/cx) attribute+cx_ :: MisoString -> Attribute action+cx_ = attr "cx"+-----------------------------------------------------------------------------+-- | [cy](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/cy) attribute+cy_ :: MisoString -> Attribute action+cy_ = attr "cy"+-----------------------------------------------------------------------------+-- | [d](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/d) attribute+d_ :: MisoString -> Attribute action+d_ = attr "d"+-----------------------------------------------------------------------------+-- | [decoding](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/decoding) attribute+--+-- @since 1.9.0.0+decoding_ :: MisoString -> Attribute action+decoding_ = attr "decoding"+-----------------------------------------------------------------------------+-- | [diffuseConstant](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/diffuseConstant) attribute+diffuseConstant_ :: MisoString -> Attribute action+diffuseConstant_ = attr "diffuseConstant"+-----------------------------------------------------------------------------+-- | [divisor](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/divisor) attribute+divisor_ :: MisoString -> Attribute action+divisor_ = attr "divisor"+-----------------------------------------------------------------------------+-- | [dur](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/dur) attribute+dur_ :: MisoString -> Attribute action+dur_ = attr "dur"+-----------------------------------------------------------------------------+-- | [dx](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/dx) attribute+dx_ :: MisoString -> Attribute action+dx_ = attr "dx"+-----------------------------------------------------------------------------+-- | [dy](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/dy) attribute+dy_ :: MisoString -> Attribute action+dy_ = attr "dy"+-----------------------------------------------------------------------------+-- | [edgeMode](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/edgeMode) attribute+edgeMode_ :: MisoString -> Attribute action+edgeMode_ = attr "edgeMode"+-----------------------------------------------------------------------------+-- | [elevation](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/elevation) attribute+elevation_ :: MisoString -> Attribute action+elevation_ = attr "elevation"+-----------------------------------------------------------------------------+-- | [end](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/end) attribute+end_ :: MisoString -> Attribute action+end_ = attr "end"+-----------------------------------------------------------------------------+-- | [exponent](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/exponent) attribute+exponent_ :: MisoString -> Attribute action+exponent_ = attr "exponent"+-----------------------------------------------------------------------------+-- | [filterUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/filterUnits) attribute+filterUnits_ :: MisoString -> Attribute action+filterUnits_ = attr "filterUnits"+-----------------------------------------------------------------------------+-- | [fr](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/fr) attribute+--+-- @since 1.9.0.0+fr_ :: MisoString -> Attribute action+fr_ = attr "fr"+-----------------------------------------------------------------------------+-- | [from](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/from) attribute+from_ :: MisoString -> Attribute action+from_ = attr "from"+-----------------------------------------------------------------------------+-- | [fx](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/fx) attribute+fx_ :: MisoString -> Attribute action+fx_ = attr "fx"+-----------------------------------------------------------------------------+-- | [fy](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/fy) attribute+fy_ :: MisoString -> Attribute action+fy_ = attr "fy"+-----------------------------------------------------------------------------+-- | [gradientTransform](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/gradientTransform) attribute+gradientTransform_ :: MisoString -> Attribute action+gradientTransform_ = attr "gradientTransform"+-----------------------------------------------------------------------------+-- | [gradientUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/gradientUnits) attribute+gradientUnits_ :: MisoString -> Attribute action+gradientUnits_ = attr "gradientUnits"+-----------------------------------------------------------------------------+-- | [in](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/in) attribute+in_' :: MisoString -> Attribute action+in_' = attr "in"+-----------------------------------------------------------------------------+-- | [in2](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/in2) attribute+in2_ :: MisoString -> Attribute action+in2_ = attr "in2"+-----------------------------------------------------------------------------+-- | [intercept](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/intercept) attribute+intercept_ :: MisoString -> Attribute action+intercept_ = attr "intercept"+-----------------------------------------------------------------------------+-- | [k1](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/k1) attribute+k1_ :: MisoString -> Attribute action+k1_ = attr "k1"+-----------------------------------------------------------------------------+-- | [k2](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/k2) attribute+k2_ :: MisoString -> Attribute action+k2_ = attr "k2"+-----------------------------------------------------------------------------+-- | [k3](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/k3) attribute+k3_ :: MisoString -> Attribute action+k3_ = attr "k3"+-----------------------------------------------------------------------------+-- | [k4](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/k4) attribute+k4_ :: MisoString -> Attribute action+k4_ = attr "k4"+-----------------------------------------------------------------------------+-- | [kernelMatrix](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/kernelMatrix) attribute+kernelMatrix_ :: MisoString -> Attribute action+kernelMatrix_ = attr "kernelMatrix"+-----------------------------------------------------------------------------+-- | [keyPoints](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/keyPoints) attribute+keyPoints_ :: MisoString -> Attribute action+keyPoints_ = attr "keyPoints"+-----------------------------------------------------------------------------+-- | [keySplines](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/keySplines) attribute+keySplines_ :: MisoString -> Attribute action+keySplines_ = attr "keySplines"+-----------------------------------------------------------------------------+-- | [keyTimes](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/keyTimes) attribute+keyTimes_ :: MisoString -> Attribute action+keyTimes_ = attr "keyTimes"+-----------------------------------------------------------------------------+-- | [lengthAdjust](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/lengthAdjust) attribute+lengthAdjust_ :: MisoString -> Attribute action+lengthAdjust_ = attr "lengthAdjust"+-----------------------------------------------------------------------------+-- | [limitingConeAngle](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/limitingConeAngle) attribute+limitingConeAngle_ :: MisoString -> Attribute action+limitingConeAngle_ = attr "limitingConeAngle"+-----------------------------------------------------------------------------+-- | [markerHeight](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/markerHeight) attribute+markerHeight_ :: MisoString -> Attribute action+markerHeight_ = attr "markerHeight"+-----------------------------------------------------------------------------+-- | [markerUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/markerUnits) attribute+markerUnits_ :: MisoString -> Attribute action+markerUnits_ = attr "markerUnits"+-----------------------------------------------------------------------------+-- | [markerWidth](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/markerWidth) attribute+markerWidth_ :: MisoString -> Attribute action+markerWidth_ = attr "markerWidth"+-----------------------------------------------------------------------------+-- | [maskContentUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/maskContentUnits) attribute+maskContentUnits_ :: MisoString -> Attribute action+maskContentUnits_ = attr "maskContentUnits"+-----------------------------------------------------------------------------+-- | [maskUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/maskUnits) attribute+maskUnits_ :: MisoString -> Attribute action+maskUnits_ = attr "maskUnits"+-----------------------------------------------------------------------------+-- | [max](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/max) attribute+max_ :: MisoString -> Attribute action+max_ = attr "max"+-----------------------------------------------------------------------------+-- | [media](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/media) attribute+media_ :: MisoString -> Attribute action+media_ = attr "media"+-----------------------------------------------------------------------------+-- | [method](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/method) attribute+method_ :: MisoString -> Attribute action+method_ = attr "method"+-----------------------------------------------------------------------------+-- | [min](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/min) attribute+min_ :: MisoString -> Attribute action+min_ = attr "min"+-----------------------------------------------------------------------------+-- | [mode](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/mode) attribute+mode_ :: MisoString -> Attribute action+mode_ = attr "mode"+-----------------------------------------------------------------------------+-- | [numOctaves](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/numOctaves) attribute+numOctaves_ :: MisoString -> Attribute action+numOctaves_ = attr "numOctaves"+-----------------------------------------------------------------------------+-- | [operator](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/operator) attribute+operator_ :: MisoString -> Attribute action+operator_ = attr "operator"+-----------------------------------------------------------------------------+-- | [order](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/order) attribute+order_ :: MisoString -> Attribute action+order_ = attr "order"+-----------------------------------------------------------------------------+-- | [orient](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/orient) attribute+orient_ :: MisoString -> Attribute action+orient_ = attr "orient"+-----------------------------------------------------------------------------+-- | [origin](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/origin) attribute+origin_ :: MisoString -> Attribute action+origin_ = attr "origin"+-----------------------------------------------------------------------------+-- | [path](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/path) attribute+path_ :: MisoString -> Attribute action+path_ = attr "path"+-----------------------------------------------------------------------------+-- | [paint-order](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/paint-order) attribute+--+-- @since 1.9.0.0+paintOrder_ :: MisoString -> Attribute action+paintOrder_ = attr "paint-order"+-----------------------------------------------------------------------------+-- | [pathLength](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/pathLength) attribute+pathLength_ :: MisoString -> Attribute action+pathLength_ = attr "pathLength"+-----------------------------------------------------------------------------+-- | [patternContentUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/patternContentUnits) attribute+patternContentUnits_ :: MisoString -> Attribute action+patternContentUnits_ = attr "patternContentUnits"+-----------------------------------------------------------------------------+-- | [patternTransform](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/patternTransform) attribute+patternTransform_ :: MisoString -> Attribute action+patternTransform_ = attr "patternTransform"+-----------------------------------------------------------------------------+-- | [patternUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/patternUnits) attribute+patternUnits_ :: MisoString -> Attribute action+patternUnits_ = attr "patternUnits"+-----------------------------------------------------------------------------+-- | [points](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/points) attribute+points_ :: MisoString -> Attribute action+points_ = attr "points"+-----------------------------------------------------------------------------+-- | [pointsAtX](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/pointsAtX) attribute+pointsAtX_ :: MisoString -> Attribute action+pointsAtX_ = attr "pointsAtX"+-----------------------------------------------------------------------------+-- | [pointsAtY](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/pointsAtY) attribute+pointsAtY_ :: MisoString -> Attribute action+pointsAtY_ = attr "pointsAtY"+-----------------------------------------------------------------------------+-- | [pointsAtZ](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/pointsAtZ) attribute+pointsAtZ_ :: MisoString -> Attribute action+pointsAtZ_ = attr "pointsAtZ"+-----------------------------------------------------------------------------+-- | [preserveAlpha](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/preserveAlpha) attribute+preserveAlpha_ :: MisoString -> Attribute action+preserveAlpha_ = attr "preserveAlpha"+-----------------------------------------------------------------------------+-- | [preserveAspectRatio](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/preserveAspectRatio) attribute+preserveAspectRatio_ :: MisoString -> Attribute action+preserveAspectRatio_ = attr "preserveAspectRatio"+-----------------------------------------------------------------------------+-- | [primitiveUnits](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/primitiveUnits) attribute+primitiveUnits_ :: MisoString -> Attribute action+primitiveUnits_ = attr "primitiveUnits"+-----------------------------------------------------------------------------+-- | [r](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/r) attribute+r_ :: MisoString -> Attribute action+r_ = attr "r"+-----------------------------------------------------------------------------+-- | [radius](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/radius) attribute+radius_ :: MisoString -> Attribute action+radius_ = attr "radius"+-----------------------------------------------------------------------------+-- | [refX](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/refX) attribute+refX_ :: MisoString -> Attribute action+refX_ = attr "refX"+-----------------------------------------------------------------------------+-- | [refY](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/refY) attribute+refY_ :: MisoString -> Attribute action+refY_ = attr "refY"+-----------------------------------------------------------------------------+-- | [repeatCount](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/repeatCount) attribute+repeatCount_ :: MisoString -> Attribute action+repeatCount_ = attr "repeatCount"+-----------------------------------------------------------------------------+-- | [repeatDur](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/repeatDur) attribute+repeatDur_ :: MisoString -> Attribute action+repeatDur_ = attr "repeatDur"+-----------------------------------------------------------------------------+-- | [restart](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/restart) attribute+restart_ :: MisoString -> Attribute action+restart_ = attr "restart"+-----------------------------------------------------------------------------+-- | [result](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/result) attribute+result_ :: MisoString -> Attribute action+result_ = attr "result"+-----------------------------------------------------------------------------+-- | [rotate](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/rotate) attribute+rotate_ :: MisoString -> Attribute action+rotate_ = attr "rotate"+-----------------------------------------------------------------------------+-- | [rx](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/rx) attribute+rx_ :: MisoString -> Attribute action+rx_ = attr "rx"+-----------------------------------------------------------------------------+-- | [ry](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/ry) attribute+ry_ :: MisoString -> Attribute action+ry_ = attr "ry"+-----------------------------------------------------------------------------+-- | [scale](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/scale) attribute+scale_ :: MisoString -> Attribute action+scale_ = attr "scale"+-----------------------------------------------------------------------------+-- | [seed](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/seed) attribute+seed_ :: MisoString -> Attribute action+seed_ = attr "seed"+-----------------------------------------------------------------------------+-- | [side](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/side) attribute+--+-- @since 1.9.0.0+side_ :: MisoString -> Attribute action+side_ = attr "side"+-----------------------------------------------------------------------------+-- | [slope](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/slope) attribute+slope_ :: MisoString -> Attribute action+slope_ = attr "slope"+-----------------------------------------------------------------------------+-- | [spacing](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/spacing) attribute+spacing_ :: MisoString -> Attribute action+spacing_ = attr "spacing"+-----------------------------------------------------------------------------+-- | [specularConstant](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/specularConstant) attribute+specularConstant_ :: MisoString -> Attribute action+specularConstant_ = attr "specularConstant"+-----------------------------------------------------------------------------+-- | [specularExponent](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/specularExponent) attribute+specularExponent_ :: MisoString -> Attribute action+specularExponent_ = attr "specularExponent"+-----------------------------------------------------------------------------+-- | [spreadMethod](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/spreadMethod) attribute+spreadMethod_ :: MisoString -> Attribute action+spreadMethod_ = attr "spreadMethod"+-----------------------------------------------------------------------------+-- | [startOffset](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/startOffset) attribute+startOffset_ :: MisoString -> Attribute action+startOffset_ = attr "startOffset"+-----------------------------------------------------------------------------+-- | [stdDeviation](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stdDeviation) attribute+stdDeviation_ :: MisoString -> Attribute action+stdDeviation_ = attr "stdDeviation"+-----------------------------------------------------------------------------+-- | [stitchTiles](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stitchTiles) attribute+stitchTiles_ :: MisoString -> Attribute action+stitchTiles_ = attr "stitchTiles"+-----------------------------------------------------------------------------+-- | [surfaceScale](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/surfaceScale) attribute+surfaceScale_ :: MisoString -> Attribute action+surfaceScale_ = attr "surfaceScale"+-----------------------------------------------------------------------------+-- | [systemLanguage](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/systemLanguage) attribute+systemLanguage_ :: MisoString -> Attribute action+systemLanguage_ = attr "systemLanguage"+-----------------------------------------------------------------------------+-- | [tableValues](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/tableValues) attribute+tableValues_ :: MisoString -> Attribute action+tableValues_ = attr "tableValues"+-----------------------------------------------------------------------------+-- | [target](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/target) attribute+target_ :: MisoString -> Attribute action+target_ = attr "target"+-----------------------------------------------------------------------------+-- | [targetX](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/targetX) attribute+targetX_ :: MisoString -> Attribute action+targetX_ = attr "targetX"+-----------------------------------------------------------------------------+-- | [targetY](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/targetY) attribute+targetY_ :: MisoString -> Attribute action+targetY_ = attr "targetY"+-----------------------------------------------------------------------------+-- | [textLength](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/textLength) attribute+textLength_ :: MisoString -> Attribute action+textLength_ = attr "textLength"+-----------------------------------------------------------------------------+-- | [to](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/to) attribute+to_ :: MisoString -> Attribute action+to_ = attr "to"+-----------------------------------------------------------------------------+-- | [transform](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/transform) attribute+transform_ :: MisoString -> Attribute action+transform_ = attr "transform"+-----------------------------------------------------------------------------+-- | [transform-origin](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/transform-origin) attribute+--+-- @since 1.9.0.0+transformOrigin_ :: MisoString -> Attribute action+transformOrigin_ = attr "transform-origin"+-----------------------------------------------------------------------------+-- | [type](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/type) attribute+type_' :: MisoString -> Attribute action+type_' = attr "type"+-----------------------------------------------------------------------------+-- | [values](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/values) attribute+values_ :: MisoString -> Attribute action+values_ = attr "values"+-----------------------------------------------------------------------------+-- | [vector-effect](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/vector-effect) attribute+--+-- @since 1.9.0.0+vectorEffect_ :: MisoString -> Attribute action+vectorEffect_ = attr "vector-effect"+-----------------------------------------------------------------------------+-- | [viewBox](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/viewBox) attribute+viewBox_ :: MisoString -> Attribute action+viewBox_ = attr "viewBox"+-----------------------------------------------------------------------------+-- | [x](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/x) attribute+x_ :: MisoString -> Attribute action+x_ = attr "x"+-----------------------------------------------------------------------------+-- | [x1](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/x1) attribute+x1_ :: MisoString -> Attribute action+x1_ = attr "x1"+-----------------------------------------------------------------------------+-- | [x2](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/x2) attribute+x2_ :: MisoString -> Attribute action+x2_ = attr "x2"+-----------------------------------------------------------------------------+-- | [xChannelSelector](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/xChannelSelector) attribute+xChannelSelector_ :: MisoString -> Attribute action+xChannelSelector_ = attr "x-channel-selector"+-----------------------------------------------------------------------------+-- | [y](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/y) attribute+y_ :: MisoString -> Attribute action+y_ = attr "y"+-----------------------------------------------------------------------------+-- | [y1](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/y1) attribute+y1_ :: MisoString -> Attribute action+y1_ = attr "y1"+-----------------------------------------------------------------------------+-- | [y2](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/y2) attribute+y2_ :: MisoString -> Attribute action+y2_ = attr "y2"+-----------------------------------------------------------------------------+-- | [yChannelSelector](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/yChannelSelector) attribute+yChannelSelector_ :: MisoString -> Attribute action+yChannelSelector_ = attr "yChannelSelector"+-----------------------------------------------------------------------------+-- | [z](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/z) attribute+z_ :: MisoString -> Attribute action+z_ = attr "z"+-----------------------------------------------------------------------------+-- | [alignment-baseline](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/alignment-baseline) attribute+alignmentBaseline_ :: MisoString -> Attribute action+alignmentBaseline_ = attr "alignment-baseline"+-----------------------------------------------------------------------------+-- | [baseline-shift](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/baseline-shift) attribute+baselineShift_ :: MisoString -> Attribute action+baselineShift_ = attr "baseline-shift"+-----------------------------------------------------------------------------+-- | [clip-path](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/clip-path) attribute+clipPath_ :: MisoString -> Attribute action+clipPath_ = attr "clip-path"+-----------------------------------------------------------------------------+-- | [clip-rule](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/clip-rule) attribute+clipRule_ :: MisoString -> Attribute action+clipRule_ = attr "clip-rule"+-----------------------------------------------------------------------------+-- | [color-interpolation](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/color-interpolation) attribute+colorInterpolation_ :: MisoString -> Attribute action+colorInterpolation_ = attr "color-interpolation"+-----------------------------------------------------------------------------+-- | [color-interpolation-filters](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/color-interpolation-filters) attribute+colorInterpolationFilters_ :: MisoString -> Attribute action+colorInterpolationFilters_ = attr "color-interpolation-filters"+-----------------------------------------------------------------------------+-- | [crossorigin](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/crossorigin) attribute+--+-- @since 1.9.0.0+crossorigin_ :: MisoString -> Attribute action+crossorigin_ = attr "crossorigin"+-----------------------------------------------------------------------------+-- | [color](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/color) attribute+color_ :: MisoString -> Attribute action+color_ = attr "color"+-----------------------------------------------------------------------------+-- | [cursor](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/cursor) attribute+cursor_ :: MisoString -> Attribute action+cursor_ = attr "cursor"+-----------------------------------------------------------------------------+-- | [direction](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/direction) attribute+direction_ :: MisoString -> Attribute action+direction_ = attr "direction"+-----------------------------------------------------------------------------+-- | [display](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/display) attribute+display_ :: MisoString -> Attribute action+display_ = attr "display"+-----------------------------------------------------------------------------+-- | [dominant-baseline](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/dominant-baseline) attribute+dominantBaseline_ :: MisoString -> Attribute action+dominantBaseline_ = attr "dominant-baseline"+-----------------------------------------------------------------------------+-- | [fill-opacity](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/fill-opacity) attribute+fillOpacity_ :: MisoString -> Attribute action+fillOpacity_ = attr "fill-opacity"+-----------------------------------------------------------------------------+-- | [fill-rule](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/fill-rule) attribute+fillRule_ :: MisoString -> Attribute action+fillRule_ = attr "fill-rule"+-----------------------------------------------------------------------------+-- | [fill](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/fill) attribute+fill_ :: MisoString -> Attribute action+fill_ = attr "fill"+-----------------------------------------------------------------------------+-- | [filter](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/filter) attribute+filter_ :: MisoString -> Attribute action+filter_ = attr "filter"+-----------------------------------------------------------------------------+-- | [flood-color](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/flood-color) attribute+floodColor_ :: MisoString -> Attribute action+floodColor_ = attr "flood-color"+-----------------------------------------------------------------------------+-- | [flood-opacity](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/flood-opacity) attribute+floodOpacity_ :: MisoString -> Attribute action+floodOpacity_ = attr "flood-opacity"+-----------------------------------------------------------------------------+-- | [font-family](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/font-family) attribute+fontFamily_ :: MisoString -> Attribute action+fontFamily_ = attr "font-family"+-----------------------------------------------------------------------------+-- | [font-size-adjust](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/font-size-adjust) attribute+fontSizeAdjust_ :: MisoString -> Attribute action+fontSizeAdjust_ = attr "font-size-adjust"+-----------------------------------------------------------------------------+-- | [font-size](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/font-size) attribute+fontSize_ :: MisoString -> Attribute action+fontSize_ = attr "font-size"+-----------------------------------------------------------------------------+-- | [font-style](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/font-style) attribute+fontStyle_ :: MisoString -> Attribute action+fontStyle_ = attr "font-style"+-----------------------------------------------------------------------------+-- | [font-variant](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/font-variant) attribute+fontVariant_ :: MisoString -> Attribute action+fontVariant_ = attr "font-variant"+-----------------------------------------------------------------------------+-- | [font-weight](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/font-weight) attribute+fontWeight_ :: MisoString -> Attribute action+fontWeight_ = attr "font-weight"+-----------------------------------------------------------------------------+-- | [image-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/image-rendering) attribute+imageRendering_ :: MisoString -> Attribute action+imageRendering_ = attr "image-rendering"+-----------------------------------------------------------------------------+-- | [letter-spacing](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/letter-spacing) attribute+letterSpacing_ :: MisoString -> Attribute action+letterSpacing_ = attr "letter-spacing"+-----------------------------------------------------------------------------+-- | [lighting-color](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/lighting-color) attribute+lightingColor_ :: MisoString -> Attribute action+lightingColor_ = attr "lighting-color"+-----------------------------------------------------------------------------+-- | [marker-end](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/marker-end) attribute+markerEnd_ :: MisoString -> Attribute action+markerEnd_ = attr "marker-end"+-----------------------------------------------------------------------------+-- | [marker-mid](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/marker-mid) attribute+markerMid_ :: MisoString -> Attribute action+markerMid_ = attr "marker-mid"+-----------------------------------------------------------------------------+-- | [marker-start](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/marker-start) attribute+markerStart_ :: MisoString -> Attribute action+markerStart_ = attr "marker-start"+-----------------------------------------------------------------------------+-- | [mask](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/mask) attribute+mask_ :: MisoString -> Attribute action+mask_ = attr "mask"+-----------------------------------------------------------------------------+-- | [opacity](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/opacity) attribute+opacity_ :: MisoString -> Attribute action+opacity_ = attr "opacity"+-----------------------------------------------------------------------------+-- | [overflow](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/overflow) attribute+overflow_ :: MisoString -> Attribute action+overflow_ = attr "overflow"+-----------------------------------------------------------------------------+-- | [pointer-events](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/pointer-events) attribute+pointerEvents_ :: MisoString -> Attribute action+pointerEvents_ = attr "pointer-events"+-----------------------------------------------------------------------------+-- | [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/shape-rendering) attribute+shapeRendering_ :: MisoString -> Attribute action+shapeRendering_ = attr "shape-rendering"+-----------------------------------------------------------------------------+-- | [stop-color](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stop-color) attribute+stopColor_ :: MisoString -> Attribute action+stopColor_ = attr "stop-color"+-----------------------------------------------------------------------------+-- | [stop-opacity](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stop-opacity) attribute+stopOpacity_ :: MisoString -> Attribute action+stopOpacity_ = attr "stop-opacity"+-----------------------------------------------------------------------------+-- | [stroke-dasharray](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke-dasharray) attribute+strokeDasharray_ :: MisoString -> Attribute action+strokeDasharray_ = attr "stroke-dasharray"+-----------------------------------------------------------------------------+-- | [stroke-dashoffset](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke-dashoffset) attribute+strokeDashoffset_ :: MisoString -> Attribute action+strokeDashoffset_ = attr "stroke-dashoffset"+-----------------------------------------------------------------------------+-- | [stroke-linecap](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke-linecap) attribute+strokeLinecap_ :: MisoString -> Attribute action+strokeLinecap_ = attr "stroke-linecap"+-----------------------------------------------------------------------------+-- | [stroke-linejoin](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke-linejoin) attribute+strokeLinejoin_ :: MisoString -> Attribute action+strokeLinejoin_ = attr "stroke-linejoin"+-----------------------------------------------------------------------------+-- | [stroke-miterlimit](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke-miterlimit) attribute+strokeMiterlimit_ :: MisoString -> Attribute action+strokeMiterlimit_ = attr "stroke-miterlimit"+-----------------------------------------------------------------------------+-- | [stroke-opacity](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke-opacity) attribute+strokeOpacity_ :: MisoString -> Attribute action+strokeOpacity_ = attr "stroke-opacity"+-----------------------------------------------------------------------------+-- | [stroke-width](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke-width) attribute+strokeWidth_ :: MisoString -> Attribute action+strokeWidth_ = attr "stroke-width"+-----------------------------------------------------------------------------+-- | [stroke](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/stroke) attribute+stroke_ :: MisoString -> Attribute action+stroke_ = attr "stroke"+-----------------------------------------------------------------------------+-- | [text-anchor](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/text-anchor) attribute+textAnchor_ :: MisoString -> Attribute action+textAnchor_ = attr "text-anchor"+-----------------------------------------------------------------------------+-- | [text-decoration](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/text-decoration) attribute+textDecoration_ :: MisoString -> Attribute action+textDecoration_ = attr "text-decoration"+-----------------------------------------------------------------------------+-- | [text-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/text-rendering) attribute+textRendering_ :: MisoString -> Attribute action+textRendering_ = attr "text-rendering"+-----------------------------------------------------------------------------+-- | [unicode-bidi](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/unicode-bidi) attribute+unicodeBidi_ :: MisoString -> Attribute action+unicodeBidi_ = attr "unicode-bidi"+-----------------------------------------------------------------------------+-- | [visibility](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/visibility) attribute+visibility_ :: MisoString -> Attribute action+visibility_ = attr "visibility"+-----------------------------------------------------------------------------+-- | [word-spacing](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/word-spacing) attribute+wordSpacing_ :: MisoString -> Attribute action+wordSpacing_ = attr "word-spacing"+-----------------------------------------------------------------------------+-- | [writing-mode](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/writing-mode) attribute+writingMode_ :: MisoString -> Attribute action+writingMode_ = attr "writing-mode"+-----------------------------------------------------------------------------
− src/Miso/TypeLevel.hs
@@ -1,19 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE TypeOperators #-}-module Miso.TypeLevel ( ToServerRoutes ) where--import Miso.Html-import Servant.API-import Servant.HTML.Lucid---- | Convert client route type to a server web handler type-type family ToServerRoutes (layout :: k) (wrapper :: * -> *) (action :: *) :: k where- ToServerRoutes (a :<|> b) wrapper action =- ToServerRoutes a wrapper action :<|>- ToServerRoutes b wrapper action- ToServerRoutes (a :> b) wrapper action =- a :> ToServerRoutes b wrapper action- ToServerRoutes (View a) wrapper action =- Get '[HTML] (wrapper (View action))
src/Miso/Types.hs view
@@ -1,149 +1,649 @@ -----------------------------------------------------------------------------+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE CPP #-}+----------------------------------------------------------------------------- -- | -- Module : Miso.Types--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable+--+-- Core types for Miso applications. ---------------------------------------------------------------------------- module Miso.Types- ( App (..)- , LogLevel (..)- , Effect- , Sub-- -- * The Transition Monad- , Transition- , mapAction- , fromTransition- , toTransition- , scheduleIO- , scheduleIO_- , scheduleIOFor_- , scheduleSub+ ( -- ** Types+ App+ , Component (..)+ , ComponentId+ , SomeComponent (..)+ , View (..)+ , Key (..)+ , Attribute (..)+ , Namespace (..)+ , CSS (..)+ , JS (..)+ , LogLevel (..)+ , VTree (..)+ , VTreeType (..)+ , Tag+ , CacheBust+ , MountPoint+ , DOMRef+ , ROOT+ , Events+ , Phase (..)+ , URI (..)+ -- ** Classes+ , ToKey (..)+ -- ** Data Bindings+ , Binding (..)+ -- ** Smart Constructors+ , emptyURI+ , component+ , vcomp+ , (-->)+ , (<--)+ , (<-->)+ , (<--->)+ , (--->)+ , (<---)+ -- ** Component mounting+ , (+>)+ , mount_+ -- ** Utils+ , getMountPoint+ , optionalAttrs+ , optionalChildren+ , prettyURI+ , prettyQueryString+ -- *** Combinators+ , node+ , vnode+ , text+ , vtext+ , text_+ , textRaw+ , textKey+ , textKey_+ , htmlEncode+ -- *** MisoString+ , MisoString+ , toMisoString+ , fromMisoString+ , ms ) where--import Control.Monad.IO.Class-import Control.Monad.Trans.Class (lift)-import Control.Monad.Trans.State.Strict (StateT(StateT), execStateT, mapStateT)-import Control.Monad.Trans.Writer.Strict (WriterT(WriterT), Writer, runWriter, tell, mapWriter)-import Data.Bifunctor (second)-import Data.Foldable (Foldable, for_)-import qualified Data.Map as M-import Miso.Effect-import Miso.FFI (JSM)-import Miso.Html.Types (View)-import Miso.String-+-----------------------------------------------------------------------------+import qualified Data.Map.Strict as M+import Data.Maybe (fromMaybe, isJust)+import Data.String (IsString, fromString)+import qualified Data.Text as T+import GHC.Generics+import Prelude+-----------------------------------------------------------------------------+import Miso.Binding ((<--), (-->), (<-->), (<---), (--->), (<--->), Binding(..))+import Miso.DSL+import Miso.Effect (Effect, Sub, Sink, DOMRef, ComponentId)+import Miso.Event.Types+import Miso.JSON (Value, ToJSON(..), encode)+import qualified Miso.String as MS+import Miso.String (ToMisoString, MisoString, toMisoString, ms, fromMisoString)+import Miso.CSS.Types (StyleSheet)+----------------------------------------------------------------------------- -- | Application entry point-data App model action = App+data Component parent model action+ = Component { model :: model- -- ^ initial model- , update :: action -> model -> Effect action model- -- ^ Function to update model, optionally providing effects.- -- See the 'Transition' monad for succinctly expressing model transitions.- , view :: model -> View action- -- ^ Function to draw `View`+ -- ^ Initial model+#ifdef SSR+ , hydrateModel :: Maybe (IO model)+#else+ , hydrateModel :: Maybe (IO model)+#endif+ -- ^ Optional 'IO' to load component 'model' state, such as reading data from page.+ -- The resulting 'model' is only used during initial hydration, not on remounts.+ , update :: action -> Effect parent model action+ -- ^ Updates model, optionally providing effects.+ , view :: model -> View model action+ -- ^ Draws 'View' , subs :: [ Sub action ]- -- ^ List of subscriptions to run during application lifetime- , events :: M.Map MisoString Bool- -- ^ List of delegated events that the body element will listen for.- -- You can start with 'Miso.Event.Types.defaultEvents' and modify as needed.- , initialAction :: action- -- ^ Initial action that is run after the application has loaded- , mountPoint :: Maybe MisoString- -- ^ Id of the root element for DOM diff. If 'Nothing' is provided, the entire document body is used as a mount point.+ -- ^ Subscriptions to run during application lifetime+ , styles :: [CSS]+ -- ^ CSS styles expressed as either a URL ('Href') or as 'Style' text.+ -- These styles are appended dynamically to the \<head\> section of your HTML page+ -- before the initial draw on \<body\> occurs.+ --+ -- @since 1.9.0.0+ , scripts :: [JS]+ -- ^ JavaScript scripts expressed as either a URL ('Src') or raw JS text.+ -- These scripts are appended dynamically to the \<head\> section of your HTML page+ -- before the initial draw on \<body\> occurs.+ --+ -- @since 1.9.0.0+ , mountPoint :: Maybe MountPoint+ -- ^ ID of the root element for DOM diff.+ -- If 'Nothing' is provided, the entire document body is used as a mount point. , logLevel :: LogLevel- -- ^ Display warning messages when prerendering if the DOM and VDOM are not in sync.+ -- ^ Debugging configuration for prerendering and event delegation+ , mailbox :: Value -> Maybe action+ -- ^ Receives mail from other components+ --+ -- @since 1.9.0.0+ , bindings :: [ Binding parent model ]+ -- ^ Data bindings between parent and child t'Miso.Types.Component's+ --+ -- @since 1.9.0.0+ , eventPropagation :: Bool+ -- ^ Should events bubble up past the t'Miso.Types.Component' barrier.+ --+ -- Defaults to t'False'+ --+ -- @since 1.9.0.0+ , mount :: Maybe action+ -- ^ action to execute during t'Miso.Types.Component' mount phase.+ --+ -- @since 1.9.0.0+ , unmount :: Maybe action+ -- ^ action to execute during t'Miso.Types.Component' unmount phase.+ --+ -- @since 1.9.0.0 }---- | Optional Logging for debugging miso internals (useful to see if prerendering is successful)+-----------------------------------------------------------------------------+-- | @mountPoint@ for t'Miso.Types.Component', e.g "body"+type MountPoint = MisoString+-----------------------------------------------------------------------------+-- | Allow users to express CSS and append it to \<head\> before the first draw+--+-- > Href "http://domain.com/style.css" (True :: CacheBust)+-- > Style "body { background-color: red; }"+--+data CSS+ = Href MisoString CacheBust+ -- ^ URL linking to hosted CSS+ | Style MisoString+ -- ^ Raw CSS content in a 'Miso.Html.Element.style_' tag+ | Sheet StyleSheet+ -- ^ CSS built with 'Miso.CSS'+ deriving (Show, Eq)+-----------------------------------------------------------------------------+-- | Parameter used to indicate cache busting logic should be used.+-- If 'True' this will append a timestamp to the query. This will force cache+-- invalidation on the browser, causing a fetch of the resources.+--+type CacheBust = Bool+-----------------------------------------------------------------------------+-- | Allow users to express JS and append it to <head> before the first draw+--+-- This is meant to be useful in development only.+--+-- @+-- Src \"http:\/\/example.com\/script.js\" (False :: CacheBust)+-- Script "alert(\"hi\");"+-- ImportMap [ "key" =: "value" ]+-- Module "console.log(\"hi\");"+-- @+--+-- @since 1.9.0.0+data JS+ = Src MisoString CacheBust+ -- ^ URL linking to hosted JS+ | Script MisoString+ -- ^ Raw JS content that you would enter in a \<script\> tag+ | Module MisoString+ -- ^ Raw JS module content that you would enter in a \<script type="module"\> tag.+ -- See [script type](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script/type)+ | ImportMap [(MisoString,MisoString)]+ -- ^ Import map content in a \<script type="importmap"\> tag.+ -- See [importmap](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script/type/importmap)+ deriving (Show, Eq)+-----------------------------------------------------------------------------+-- | Convenience for extracting mount point+getMountPoint :: Maybe MisoString -> MisoString+getMountPoint = fromMaybe "body"+-----------------------------------------------------------------------------+-- | Smart constructor for t'Miso.Types.Component' with sane defaults.+component+ :: model+ -- ^ model+ -> (action -> Effect parent model action)+ -- ^ update+ -> (model -> View model action)+ -- ^ view+ -> Component parent model action+component m u v = Component+ { model = m+ , hydrateModel = Nothing+ , update = u+ , view = v+ , subs = []+ , styles = []+ , scripts = []+ , mountPoint = Nothing+ , logLevel = Off+ , mailbox = const Nothing+ , bindings = []+ , eventPropagation = False+ , mount = Nothing+ , unmount = Nothing+ }+-----------------------------------------------------------------------------+-- | Synonym for 'component'+vcomp+ :: model+ -- ^ model+ -> (action -> Effect parent model action)+ -- ^ update+ -> (model -> View model action)+ -- ^ view+ -> Component parent model action+vcomp = component +-----------------------------------------------------------------------------+-- | A top-level t'Miso.Types.Component' can have no @parent@.+--+-- The 'ROOT' type is for disallowing a top-level mounted t'Miso.Types.Component' access+-- into its parent state. It has no inhabitants (spiritually 'Data.Void.Void')+--+data ROOT+-----------------------------------------------------------------------------+-- | 'Eq' instance for 'ROOT'+instance Eq ROOT where _ == _ = True+-----------------------------------------------------------------------------+-- | A miso application is a top-level t'Miso.Types.Component', which has no @parent@.+-- This is enforced by specializing the @parent@ type parameter to 'ROOT'.+--+type App model action = Component ROOT model action+-----------------------------------------------------------------------------+-- | Logging configuration for debugging Miso internals (useful to see if prerendering is successful) data LogLevel = Off- | DebugPrerender+ -- ^ No debug logging, the default value used in 'component'+ | DebugHydrate+ -- ^ Will warn if the structure or properties of the+ -- DOM vs. Virtual DOM differ during prerendering.+ | DebugEvents+ -- ^ Will warn if an event cannot be routed to the Haskell event+ -- handler that raised it. Also will warn if an event handler is+ -- being used, yet it's not being listened for by the event+ -- delegator mount point.+ | DebugAll+ -- ^ Logs on all of the above deriving (Show, Eq)---- | A monad for succinctly expressing model transitions in the 'update' function.+-----------------------------------------------------------------------------+-- | Tag type, (e.g. 'div_', 'p_') ----- @Transition@ is a state monad so it abstracts over manually passing the model--- around. It's also a writer monad where the accumulator is a list of scheduled--- IO actions. Multiple actions can be scheduled using--- @Control.Monad.Writer.Class.tell@ from the @mtl@ library and a single action--- can be scheduled using 'scheduleIO'.+-- Meant to indicate the type of element being created.+-- Used as the first argument to @document.createElement@ for the web backend. ----- Tip: use the @Transition@ monad in combination with the stateful--- <http://hackage.haskell.org/package/lens-4.15.4/docs/Control-Lens-Operators.html lens>--- operators (all operators ending in "@=@"). The following example assumes--- the lenses @field1@, @counter@ and @field2@ are in scope and that the--- @LambdaCase@ language extension is enabled:+type Tag = MisoString+-----------------------------------------------------------------------------+-- | Core type for constructing a virtual DOM in Haskell+data View model action+ = VNode Namespace Tag [Attribute action] [View model action]+ | VText (Maybe Key) MisoString+ | VComp (Maybe Key) (SomeComponent model)+ deriving Functor+-----------------------------------------------------------------------------+-- | Existential wrapper allowing nesting of t'Miso.Types.Component' in t'Miso.Types.Component'+data SomeComponent parent+ = forall model action . Eq model+ => SomeComponent (Component parent model action)+-----------------------------------------------------------------------------+-- | t'Miso.Types.Component' mounting combinator --+-- Used in the @view@ function to mount a t'Miso.Types.Component' on any 'VNode'.+-- -- @--- myApp = App--- { update = 'fromTransition' . \\case--- MyAction1 -> do--- field1 .= value1--- counter += 1--- MyAction2 -> do--- field2 %= f--- scheduleIO $ do--- putStrLn \"Hello\"--- putStrLn \"World!\"--- , ...--- }+-- "component-id" +> component model noop $ \\m ->+-- div_ [ id_ "foo" ] [ text (ms m) ] -- @-type Transition action model = StateT model (Writer [Sub action])---- | Turn a transition that schedules subscriptions that consume--- actions of type @a@ into a transition that schedules subscriptions--- that consume actions of type @b@ using the supplied function of--- type @a -> b@.-mapAction :: (actionA -> actionB) -> Transition actionA model r -> Transition actionB model r-mapAction = mapStateT . mapWriter . second . fmap . mapSub---- | Convert a @Transition@ computation to a function that can be given to 'update'.-fromTransition- :: Transition action model ()- -> (model -> Effect action model) -- ^ model 'update' function.-fromTransition act = uncurry Effect . runWriter . execStateT act---- | Convert an 'update' function to a @Transition@ computation.-toTransition- :: (model -> Effect action model) -- ^ model 'update' function- -> Transition action model ()-toTransition f = StateT $ \s ->- let Effect s' ios = f s- in WriterT $ pure (((), s'), ios)---- | Schedule a single IO action for later execution. ----- Note that multiple IO action can be scheduled using--- @Control.Monad.Writer.Class.tell@ from the @mtl@ library.-scheduleIO :: JSM action -> Transition action model ()-scheduleIO ioAction = scheduleSub $ \sink -> ioAction >>= liftIO . sink---- | Like 'scheduleIO' but doesn't cause an action to be dispatched to--- the 'update' function.+-- @since 1.9.0.0+(+>)+ :: forall child model action a . Eq child+ => MisoString+ -- ^ 'VComp' 'key_'+ -> Component model child action+ -- ^ 'Component'+ -> View model a+infixr 0 +>+key +> comp = VComp (Just (toKey key)) (SomeComponent comp)+-----------------------------------------------------------------------------+-- | t'Miso.Types.Component' mounting combinator. ----- This is handy for scheduling IO computations where you don't care--- about their results or when they complete.-scheduleIO_ :: JSM () -> Transition action model ()-scheduleIO_ ioAction = scheduleSub $ \_sink -> ioAction---- | Like `scheduleIO_` but generalized to any instance of `Foldable`+-- Note: only use this if you're certain you won't be diffing two t'Miso.Types.Component'+-- against each other. Otherwise, you will need a key to distinguish between+-- the two t'Miso.Types.Component', to ensure unmounting and mounting occurs. ----- This is handy for scheduling IO computations that return a `Maybe` value-scheduleIOFor_ :: Foldable f => JSM (f action) -> Transition action model ()-scheduleIOFor_ io = scheduleSub $ \sink -> io >>= \m -> liftIO (for_ m sink)---- | Like 'scheduleIO' but schedules a subscription which is an IO--- computation that has access to a 'Sink' which can be used to--- asynchronously dispatch actions to the 'update' function.+-- @+-- mount_ $ component model noop $ \\m ->+-- div_ [ id_ "foo" ] [ text (ms m) ]+-- @ ----- A use-case is scheduling an IO computation which creates a--- 3rd-party JS widget which has an associated callback. The callback--- can then call the sink to turn events into actions. To do this--- without accessing a sink requires going via a @'Sub'scription@--- which introduces a leaky-abstraction.-scheduleSub :: Sub action -> Transition action model ()-scheduleSub sub = lift $ tell [ sub ]+-- @since 1.9.0.0+mount_+ :: Eq child+ => Component model child a+ -- ^ 'Component' to mount+ -> View model action+mount_ comp = VComp Nothing (SomeComponent comp)+-----------------------------------------------------------------------------+-- | DOM element namespace.+data Namespace+ = HTML+ -- ^ HTML Namespace+ | SVG+ -- ^ SVG Namespace+ | MATHML+ -- ^ MATHML Namespace+ deriving (Show, Eq)+-----------------------------------------------------------------------------+instance ToJSVal Namespace where+ toJSVal = \case+ SVG -> toJSVal ("svg" :: MisoString)+ HTML -> toJSVal ("html" :: MisoString)+ MATHML -> toJSVal ("mathml" :: MisoString)+-----------------------------------------------------------------------------+-- | Unique key for a DOM node.+--+-- This key is only used to speed up diffing the children of a DOM+-- node, the actual content is not important. The keys of the children+-- of a given DOM node must be unique. Failure to satisfy this+-- invariant gives undefined behavior at runtime.+newtype Key = Key MisoString+ deriving newtype (Show, Eq, IsString, ToJSON, ToMisoString)+-----------------------------------------------------------------------------+-- | ToJSVal instance for t'Key'+instance ToJSVal Key where+ toJSVal (Key x) = toJSVal x+-----------------------------------------------------------------------------+-- | Convert custom key types to t'Key'.+--+-- Instances of this class do not have to guarantee uniqueness of the+-- generated keys, it is up to the user to do so. @toKey@ must be an+-- injective function (different inputs must map to different outputs).+class ToKey key where+ -- | Converts any key into t'Key'+ toKey :: key -> Key+-----------------------------------------------------------------------------+-- | Identity instance+instance ToKey Key where toKey = id+-----------------------------------------------------------------------------+#ifndef VANILLA+-- | Convert 'MisoString' to t'Key'+instance ToKey MisoString where toKey = Key+#endif+-----------------------------------------------------------------------------+-- | Convert 'T.Text' to t'Key'+instance ToKey T.Text where toKey = Key . toMisoString+-----------------------------------------------------------------------------+-- | Convert 'String' to t'Key'+instance ToKey String where toKey = Key . toMisoString+-----------------------------------------------------------------------------+-- | Convert 'Int' to t'Key'+instance ToKey Int where toKey = Key . toMisoString+-----------------------------------------------------------------------------+-- | Convert 'Double' to t'Key'+instance ToKey Double where toKey = Key . toMisoString+-----------------------------------------------------------------------------+-- | Convert 'Float' to t'Key'+instance ToKey Float where toKey = Key . toMisoString+-----------------------------------------------------------------------------+-- | Convert 'Word' to t'Key'+instance ToKey Word where toKey = Key . toMisoString+-----------------------------------------------------------------------------+-- | Attribute of a vnode in a t'View'.+--+data Attribute action+ = Property MisoString Value+ | ClassList [MisoString]+ | On (Sink action -> VTree -> LogLevel -> Events -> IO ())+ -- ^ The @Sink@ callback can be used to dispatch actions which are fed back to+ -- the @update@ function. This is especially useful for event handlers+ -- like the @onclick@ attribute. The second argument represents the+ -- vnode the attribute is attached to.+ | Styles (M.Map MisoString MisoString)+ deriving Functor+-----------------------------------------------------------------------------+instance Eq (Attribute action) where+ Property k1 v1 == Property k2 v2 = k1 == k2 && v1 == v2+ ClassList x == ClassList y = x == y+ Styles x == Styles y = x == y+ _ == _ = False+-----------------------------------------------------------------------------+instance Show (Attribute action) where+ show = \case+ Property key value ->+ MS.unpack key <> "=" <> MS.unpack (ms (encode value))+ ClassList classes ->+ MS.unpack (MS.intercalate " " classes)+ On _ ->+ "<event-handler>"+ Styles styles ->+ MS.unpack $ MS.concat+ [ k <> "=" <> v <> ";"+ | (k, v) <- M.toList styles+ ]+-----------------------------------------------------------------------------+-- | 'IsString' instance+instance IsString (View model action) where+ fromString = VText Nothing . fromString+-----------------------------------------------------------------------------+-- | Virtual DOM implemented as a JavaScript t'Object'.+-- Used for diffing, patching and event delegation.+-- Not meant to be constructed directly, see t'Miso.Types.View' instead.+newtype VTree = VTree { getTree :: Object }+ deriving newtype (ToObject, ToJSVal)+-----------------------------------------------------------------------------+-- | Create a new 'Miso.Types.VNode'.+--+-- @node ns tag attrs children@ creates a new node with tag @tag@+-- in the namespace @ns@. All @attrs@ are called when+-- the node is created and its children are initialized to @children@.+node+ :: Namespace+ -> MisoString+ -> [Attribute action]+ -> [View model action]+ -> View model action+node = VNode+-----------------------------------------------------------------------------+-- | Create a new 'Miso.Types.VNode'.+--+-- Synonym for 'node'+--+vnode+ :: Namespace+ -> MisoString+ -> [Attribute action]+ -> [View model action]+ -> View model action+vnode = node+-----------------------------------------------------------------------------+-- | Create a new v'VText' with the given content.+text :: MisoString -> View model action+#ifdef SSR+text = VText Nothing . htmlEncode+#else+text = VText Nothing+#endif+-----------------------------------------------------------------------------+-- | Synonym for 'text'+vtext :: MisoString -> View model action+vtext = text+----------------------------------------------------------------------------+-- | Create a new v'VText', not subject to HTML escaping.+--+-- Like 'text', except will not escape HTML when used on the server.+--+textRaw :: MisoString -> View model action+textRaw = VText Nothing+----------------------------------------------------------------------------+-- |+-- HTML-encodes text.+--+-- Useful for escaping HTML when delivering on the server. Naive usage+-- of 'text' will ensure this as well.+--+-- >>> Data.Text.IO.putStrLn $ text "<a href=\"\">"+-- <a href="">+htmlEncode :: MisoString -> MisoString+htmlEncode = MS.concatMap $ \case+ '<' -> "<"+ '>' -> ">"+ '&' -> "&"+ '"' -> """+ '\'' -> "'"+ x -> MS.singleton x+-----------------------------------------------------------------------------+-- | Create a new v'VText' containing concatenation of the given strings.+--+-- @+-- view :: View model action+-- view = div_+-- [ className "container" ]+-- [ text_+-- [ "foo"+-- , "bar"+-- ]+-- ]+-- @+--+-- Renders as @<div class="container">foo bar</div>@+--+-- A single additional space is added between elements.+--+text_ :: [MisoString] -> View model action+text_ = VText Nothing . MS.intercalate " "+-----------------------------------------------------------------------------+-- | Like 'text', but allow the node to be keyed for efficient diffing.+--+-- @+-- view :: model -> View model action+-- view = \x -> div_ [] [ textKey (1 :: Int) "text here" ]+-- @+--+-- @since 1.9.0.0+textKey :: ToKey key => key -> MisoString -> View model action+textKey k = VText (Just (toKey k))+-----------------------------------------------------------------------------+-- | Like 'text_', but allow the node to be keyed for efficient diffing.+--+-- @+-- view :: model -> View model action+-- view = \x -> div_ [] [ textKey_ (1 :: Int) [ "text", "goes", "here" ] ]+-- @+--+-- @since 1.9.0.0+textKey_ :: ToKey key => key -> [MisoString] -> View model action+textKey_ k xs = VText (Just (toKey k)) (MS.intercalate " " xs)+-----------------------------------------------------------------------------+-- | Utility function to make it easy to specify conditional attributes+--+-- @+-- view :: Bool -> View model action+-- view danger = optionalAttrs textarea_ [ id_ "txt" ] danger [ class_ "danger" ] ["child"]+-- @+--+-- @since 1.9.0.0+optionalAttrs+ :: ([Attribute action] -> [View model action] -> View model action)+ -> [Attribute action] -- ^ Attributes to be added unconditionally+ -> Bool -- ^ A condition+ -> [Attribute action] -- ^ Additional attributes to add if the condition is True+ -> [View model action] -- ^ Children+ -> View model action+optionalAttrs element attrs condition opts kids =+ case element attrs kids of+ VNode ns name _ _ -> do+ let newAttrs = concat [ opts | condition ] ++ attrs+ VNode ns name newAttrs kids+ x -> x+----------------------------------------------------------------------------+-- | Conditionally adds children.+--+-- @+-- view :: Bool -> View model action+-- view withChild = optionalChildren div_ [ id_ "txt" ] [] withChild [ "foo" ]+-- @+--+-- @since 1.9.0.0+optionalChildren+ :: ([Attribute action] -> [View model action] -> View model action)+ -> [Attribute action] -- ^ Attributes to be added unconditionally+ -> [View model action] -- ^ Children to be added unconditionally+ -> Bool -- ^ A condition+ -> [View model action] -- ^ Additional children to add if the condition is True+ -> View model action+optionalChildren element attrs kids condition opts =+ case element attrs kids of+ VNode ns name _ _ -> do+ let newKids = kids ++ concat [ opts | condition ]+ VNode ns name attrs newKids+ x -> x+----------------------------------------------------------------------------+-- | URI type. See the official [specification](https://www.rfc-editor.org/rfc/rfc3986)+--+data URI+ = URI+ { uriPath, uriFragment :: MisoString+ , uriQueryString :: M.Map MisoString (Maybe MisoString)+ } deriving stock (Show, Eq, Generic)+ deriving anyclass (ToJSVal, ToObject)+----------------------------------------------------------------------------+-- | Empty t'URI'.+emptyURI :: URI+emptyURI = URI mempty mempty mempty+----------------------------------------------------------------------------+instance ToMisoString URI where+ toMisoString = prettyURI+----------------------------------------------------------------------------+-- | Pretty-prints a t'URI'.+prettyURI :: URI -> MisoString+prettyURI uri@URI {..} = "/" <> uriPath <> prettyQueryString uri <> uriFragment+-----------------------------------------------------------------------------+-- | Pretty-prints a t'URI' query string.+prettyQueryString :: URI -> MisoString+prettyQueryString URI {..} = queries <> flags+ where+ queries =+ MS.concat+ [ "?" <>+ MS.intercalate "&"+ [ k <> "=" <> v+ | (k, Just v) <- M.toList uriQueryString+ ]+ | any isJust (M.elems uriQueryString)+ ]+ flags = mconcat+ [ "?" <> k+ | (k, Nothing) <- M.toList uriQueryString+ ]+-----------------------------------------------------------------------------+-- | VTreeType ADT for matching TypeScript enum+data VTreeType+ = VCompType+ | VNodeType+ | VTextType+ deriving (Show, Eq)+-----------------------------------------------------------------------------+instance ToJSVal VTreeType where+ toJSVal = \case+ VCompType -> toJSVal (0 :: Int)+ VNodeType -> toJSVal (1 :: Int)+ VTextType -> toJSVal (2 :: Int)+-----------------------------------------------------------------------------
src/Miso/Util.hs view
@@ -1,22 +1,34 @@ ----------------------------------------------------------------------------- -- | -- Module : Miso.Util--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable+--+-- Utility functions for views, parsing, and general purpose combinators. ---------------------------------------------------------------------------- module Miso.Util ( withFoldable , conditionalViews+ , oneOf+ , enclosed+ , optionalDefault+ , exists+ , sepBy1+ , sepBy+ , between , (=:)+ , compose ) where--import Data.Foldable-import qualified Data.Map as M-import Miso.Html (View)-+-----------------------------------------------------------------------------+import Control.Category+import Data.Maybe (isJust, fromMaybe)+import Control.Applicative (Alternative, many, empty, (<|>), optional)+import Data.Foldable (toList)+import Prelude hiding ((.))+----------------------------------------------------------------------------- -- | Generic @map@ function, useful for creating @View@s from the elements of -- some @Foldable@. Particularly handy for @Maybe@, as shown in the example -- below.@@ -24,25 +36,94 @@ -- @ -- view model = -- div_ [] $--- withFoldable (model ^. mSomeMaybeVal) $ \someVal ->+-- withFoldable (model ^. mSomeMaybeVal) $ \\someVal -> -- p_ [] [ text $ "Hey, look at this value: " <> ms (show someVal) ] -- @ withFoldable :: Foldable t => t a -> (a -> b) -> [b] withFoldable ta f = map f (toList ta)---- | Hides the @View@s the condition is False. Shows them when the condition+-----------------------------------------------------------------------------+-- | Conditionally includes views.+-- Hides the 'Miso.Types.View's if the condition is False. Shows them when the condition -- is True.-conditionalViews :: Bool -> [View action] -> [View action]+conditionalViews :: Bool -> [view] -> [view] conditionalViews condition views = if condition then views else []---- | Smart constructor for Attributes. This function is helpful when constructing numerous Attributes--- Example shown below.--- --- @ --- div_ [ style_ $ ("background" =: "red" <> "width" =: "250px" <> "height" =: "250px") ] []+-----------------------------------------------------------------------------+-- | Selects the first 'Alternative', analogous to 'Data.Foldable.asum'.+oneOf :: Alternative f => [f a] -> f a+oneOf = foldr (<|>) empty+----------------------------------------------------------------------------+-- | Convenience function for constructing parser / lexer combinators.+-- -- @-(=:) :: k -> a -> M.Map k a -a =: b = M.singleton a b+-- test :: Parser a -> Parser a+-- test = enclosed (char '(') (char ')')+-- @+enclosed :: Applicative f => f a -> f b -> f c -> f c+enclosed l r x = l *> x <* r+----------------------------------------------------------------------------+-- | Allow the specification of default values during parsing / lexing+-- in the case of parser / lexer failure.+--+-- @+-- test :: Parser MisoString+-- test = optionalDefault "foo" (string "bar")+-- @+optionalDefault :: Alternative f => b -> f b -> f b+optionalDefault def p = fromMaybe def <$> optional p+----------------------------------------------------------------------------+-- | Combinator for testing parsing / lexing failure on any input.+--+-- @+-- test :: Parser Bool+-- test = exists (string "foo")+-- @+exists :: Alternative f => f a -> f Bool+exists p = isJust <$> optional p+----------------------------------------------------------------------------+-- | Interleaves one parser combinator with another, must have at least one+-- successful parse.+--+-- @+-- test :: Parser [Int]+-- test = sepBy1 (char ',') number+-- @+sepBy1 :: Alternative m => m sep -> m a -> m [a]+sepBy1 sep p = (:) <$> p <*> many (sep *> p)+----------------------------------------------------------------------------+-- | Interleaves one parser combinator with another, may not have any successful+-- parses.+--+-- @+-- test :: Parser [Int]+-- test = sepBy (char ',') number+-- @+sepBy :: Alternative m => m sep -> m a -> m [a]+sepBy sep p = sepBy1 sep p <|> pure []+----------------------------------------------------------------------------+-- | Successfully parses the arguments between another combinator+--+-- @+-- test :: Parser (Int, Int)+-- test = between (char '*') number number+-- -- 5*5+-- @+between :: Applicative f => f a -> f b -> f c -> f (b, c)+between c l r = (,) <$> l <*> (c *> r)+----------------------------------------------------------------------------+-- | Tuple constructor, useful for constructing key-value pairs.+--+(=:) :: k -> v -> (k, v)+k =: v = (k,v)+----------------------------------------------------------------------------+-- | Function composition generalized to 'Category'+--+-- @+-- test :: Int -> Int+-- test = (+1) \`compose\` (+1)+-- @+compose :: Category cat => cat a b -> cat b c -> cat a c+compose = flip (.)+----------------------------------------------------------------------------
+ src/Miso/Util/Lexer.hs view
@@ -0,0 +1,231 @@+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Util.Lexer+-- Copyright : (C) 2016-2026 David M. Johnson (@dmjio)+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+----------------------------------------------------------------------------+module Miso.Util.Lexer+ ( -- ** Types+ Lexer (..)+ , Stream (..)+ , Located (..)+ , Location (..)+ , LexerError (..)+ -- ** Combinators+ , getStartColumn+ , zeroLocation+ , initialLocation+ , mkStream+ , oops+ , streamError+ , string+ , string'+ , char+ , satisfy+ , peek+ , getInput+ , putInput+ , getLocation+ , setLocation+ , modifyInput+ , withLocation+ ) where+----------------------------------------------------------------------------+import Control.Monad+import Control.Applicative+----------------------------------------------------------------------------+import Miso.String (MisoString, ToMisoString)+import qualified Miso.String as MS+----------------------------------------------------------------------------+-- | Potential errors during lexing+data LexerError+ = LexerError MisoString Location+ | UnexpectedEOF Location+ deriving (Eq)+----------------------------------------------------------------------------+instance Show LexerError where+ show (UnexpectedEOF loc) =+ "Unexpected EOF at: " <> show loc+ show (LexerError xs loc) =+ "Unexpected \"" <> take 5 (MS.unpack xs) <> "\"... at " <> show loc+----------------------------------------------------------------------------+-- | Type to hold the location (line and column) of a Token+data Location+ = Location+ { line :: Int+ , column :: (Int,Int)+ } deriving Eq+----------------------------------------------------------------------------+instance Show Location where+ show (Location l col) = show l <> " " <> show col+----------------------------------------------------------------------------+-- | Helper for extracting column from t'Location'+getStartColumn :: Location -> Int+getStartColumn = fst . column+----------------------------------------------------------------------------+-- | Initial t'Location'+initialLocation :: Location+initialLocation = Location 1 (1,1)+----------------------------------------------------------------------------+-- | Empty t'Location'+zeroLocation :: Location+zeroLocation = Location 0 (0,0)+----------------------------------------------------------------------------+-- | A Lexer is a state monad with optional failure the abides by the+-- maximal munch rule in its 'Alternative' instance.+newtype Lexer token+ = Lexer+ { runLexer :: Stream -> Either LexerError (token, Stream)+ }+----------------------------------------------------------------------------+-- | Combinator that always fails to lex+oops :: Lexer token+oops = Lexer $ \s -> Left (streamError s)+----------------------------------------------------------------------------+-- | Smart constructor for t'LexerError'+streamError :: Stream -> LexerError+streamError (Stream xs l) = unexpected xs l+----------------------------------------------------------------------------+-- | Smart constructor for t'Stream'+mkStream :: MisoString -> Stream+mkStream xs = Stream xs initialLocation+----------------------------------------------------------------------------+-- | A t'Stream' of text used as input to lexing+data Stream+ = Stream+ { stream :: MisoString+ -- ^ Current t'Stream' of text+ , currentLocation :: Location+ -- ^ current t'Location' in the t'Stream'+ } deriving Eq+----------------------------------------------------------------------------+-- | A t'Located' token holds the lexed output the t'Location' at which+-- the successful lex occurred.+data Located token+ = Located+ { token :: token+ , location :: Location+ } deriving Eq+----------------------------------------------------------------------------+instance Show token => Show (Located token) where+ show (Located t l) = show l <> " " <> show t+----------------------------------------------------------------------------+instance Functor Lexer where+ fmap f (Lexer l) = Lexer $ \input -> do+ (t, x) <- l input+ pure (f t, x)+----------------------------------------------------------------------------+instance Applicative Lexer where+ pure x = Lexer $ \input -> pure (x, input)+ Lexer l1 <*> Lexer l2 = Lexer $ \input -> do+ (f, x) <- l1 input+ (a, y) <- l2 x+ pure (f a, y)+----------------------------------------------------------------------------+instance Monad Lexer where+ m >>= f = Lexer $ \input -> do+ (x, s) <- runLexer m input+ runLexer (f x) s+----------------------------------------------------------------------------+instance Alternative Lexer where+ empty = Lexer $ \(Stream s l) -> Left (unexpected s l)+ Lexer l1 <|> Lexer l2 = Lexer $ \input ->+ case (l1 input, l2 input) of+ (res, Left _) -> res+ (Left _, res) -> res+ (Right (x, Stream s sl), Right (y,Stream t tl)) ->+ if MS.length s <= MS.length t+ then Right (x, Stream s sl)+ else Right (y, Stream t tl)+----------------------------------------------------------------------------+instance MonadPlus Lexer where+ mplus = (<|>)+----------------------------------------------------------------------------+-- | Fetches the first character in the t'Stream', does not consume input+peek :: Lexer (Maybe Char)+peek = Lexer $ \ys ->+ pure $ case ys of+ Stream xs l ->+ case MS.uncons xs of+ Nothing -> (Nothing, Stream mempty l)+ Just (z,zs) -> (Just z, Stream (MS.singleton z <> zs) l)+----------------------------------------------------------------------------+-- | Predicate combinator that consumes matching input+satisfy :: (Char -> Bool) -> Lexer Char+satisfy predicate = Lexer $ \ys ->+ case ys of+ Stream s l ->+ case MS.uncons s of+ Nothing -> Left (unexpected s l)+ Just (z,zs)+ | predicate z -> Right (z, Stream zs l)+ | otherwise -> Left (unexpected zs l)+----------------------------------------------------------------------------+-- | Smart constructor for t'LexerError'+-- If the input is empty, an 'UnexpectedEOF' is issued.+unexpected :: MisoString -> Location -> LexerError+unexpected xs loc | MS.null xs = UnexpectedEOF loc+unexpected cs loc = LexerError cs loc+----------------------------------------------------------------------------+-- | Retrieves current input from t'Lexer'+getInput :: Lexer Stream+getInput = Lexer $ \s -> Right (s, s)+----------------------------------------------------------------------------+-- | Overrides current t'Stream' in t'Lexer' to user-specified t'Stream'.+putInput :: Stream -> Lexer ()+putInput s = Lexer $ \_ -> Right ((), s)+----------------------------------------------------------------------------+-- | Retrieves the current t'Stream' t'Location'+getLocation :: Lexer Location+getLocation = Lexer $ \(Stream s l) -> pure (l, Stream s l)+----------------------------------------------------------------------------+-- | Sets the current t'Stream' t'Location'+setLocation :: Location -> Lexer ()+setLocation l = Lexer $ \(Stream s _) -> pure ((), Stream s l)+----------------------------------------------------------------------------+-- | Modifies a t'Stream'+modifyInput :: (Stream -> Stream) -> Lexer ()+modifyInput f = do+ s <- getInput+ putInput (f s)+----------------------------------------------------------------------------+-- | Lexer combinator for matching a 'Char'+char :: Char -> Lexer Char+char c = satisfy (== c)+----------------------------------------------------------------------------+-- | Lexer combinator for matching a 'String'+string' :: String -> Lexer String+string' = traverse char+----------------------------------------------------------------------------+-- | Lexer combinator for matching a 'MisoString'+string :: MisoString -> Lexer MisoString+string prefix = Lexer $ \s ->+ case s of+ Stream ys l+ | prefix `MS.isPrefixOf` ys ->+ Right (prefix, Stream (MS.drop (MS.length prefix) ys) l)+ | otherwise ->+ Left (unexpected ys l)+----------------------------------------------------------------------------+-- | Lexer combinator for executing a t'Lexer' with annotated t'Location' information+withLocation :: ToMisoString token => Lexer token -> Lexer (Located token)+withLocation lexer = do+ result <- lexer+ let+ adjustLoc :: Location -> MisoString -> Location+ adjustLoc l = MS.foldl' adjust (next l)++ setLocation =<< adjustLoc <$> getLocation <*> pure (MS.ms result)+ Located result <$> getLocation+ where+ next :: Location -> Location+ next (Location l (_, end)) = Location l (end, end)++ adjust :: Location -> Char -> Location+ adjust (Location l (_, _)) '\n' = Location (l + 1) (1,1)+ adjust (Location l (start, end)) '\t' = Location l (start, end + 8)+ adjust (Location l (start, end)) _ = Location l (start, end + 1)+----------------------------------------------------------------------------
+ src/Miso/Util/Parser.hs view
@@ -0,0 +1,146 @@+-----------------------------------------------------------------------------+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE CPP #-}+-----------------------------------------------------------------------------+-- |+-- Module : Miso.Util.Parser+-- Copyright : (C) 2016-2026 David M. Johnson (@dmjio)+-- License : BSD3-style (see the file LICENSE)+-- Maintainer : David M. Johnson <code@dmj.io>+-- Stability : experimental+-- Portability : non-portable+----------------------------------------------------------------------------+module Miso.Util.Parser+ ( -- ** Types+ Parser+ , ParserT (..)+ , ParseError (..)+ -- ** Combinators+ , parse+ , anyToken+ , satisfy+ , peek+ , token_+ , errorOut+ , allTokens+ , modifyTokens+ , askParser+ , endOfInput+ ) where+----------------------------------------------------------------------------+#if __GLASGOW_HASKELL__ <= 881+import Control.Monad.Fail (MonadFail (..))+#endif+import Control.Applicative+import Control.Monad+import Data.Maybe (isNothing)+----------------------------------------------------------------------------+import Miso.Util.Lexer (LexerError)+----------------------------------------------------------------------------+-- | A type for expressing failure during parsing.+data ParseError a token+ = UnexpectedParse [token]+ | LexicalError LexerError+ | Ambiguous [(a, [token])]+ | NoParses token+ | EmptyStream+ deriving (Show, Eq)+----------------------------------------------------------------------------+-- | Executes a parser against a series of tokens.+parse :: Parser token a -> [token] -> Either (ParseError a token) a+parse _ [] = Left EmptyStream+parse parser tokens =+ case runParserT parser () tokens of+ [] -> Left (NoParses (last tokens))+ [(x, [])] -> Right x+ [(_, xs)] -> Left (UnexpectedParse xs)+ xs -> Left (Ambiguous xs)+----------------------------------------------------------------------------+-- | Convenience synonym when defining parser combinators+type Parser token a = ParserT () [token] [] a+----------------------------------------------------------------------------+-- | Core type for parsing+newtype ParserT r token m a+ = Parser+ { runParserT :: r -> token -> m (a, token)+ }+----------------------------------------------------------------------------+instance Functor (ParserT r token []) where+ fmap f (Parser run) = Parser $ \r input ->+ case run r input of+ tokens -> [ (f x, toks) | (x, toks) <- tokens ]+----------------------------------------------------------------------------+instance Applicative (ParserT r token []) where+ pure x = Parser $ \_ s -> pure (x,s)+ Parser f <*> Parser g = Parser $ \r input -> do+ (k, s) <- f r input+ (x, t) <- g r s+ pure (k x, t)+----------------------------------------------------------------------------+instance Alternative (ParserT r token []) where+ empty = Parser $ \_ _ -> []+ Parser f <|> Parser g =+ Parser $ \r tokens ->+ case f r tokens of+ [] -> g r tokens+ x -> x+----------------------------------------------------------------------------+instance Monad (ParserT r token []) where+ return = pure+ Parser f >>= k = Parser $ \r tokens -> do+ (x, tokens') <- f r tokens+ runParserT (k x) r tokens'+----------------------------------------------------------------------------+instance MonadFail (ParserT r token []) where+ fail _ = empty+----------------------------------------------------------------------------+instance MonadPlus (ParserT r token [])+----------------------------------------------------------------------------+-- | Match any token.+anyToken :: ParserT r [a] [] a+anyToken = Parser $ \_ input ->+ case input of+ t : ts -> [(t, ts)]+ _ -> []+----------------------------------------------------------------------------+-- | Succeeds for any token for which the predicate @f@ returns 'True'.+-- Returns the parsed token.+satisfy :: (a -> Bool) -> ParserT r [a] [] a+satisfy f = do+ t <- anyToken+ guard (f t)+ pure t+----------------------------------------------------------------------------+-- | Succeeds if the next token in the stream matches the given one.+-- Returns the parsed token.+token_ :: Eq token => token -> Parser token token+token_ t = satisfy (==t)+----------------------------------------------------------------------------+-- | Returns all input from a parser+allTokens :: ParserT r a [] a+allTokens = Parser $ \_ input -> [(input, input)]+----------------------------------------------------------------------------+-- | Modifies tokens+modifyTokens :: (t -> t) -> ParserT r t [] ()+modifyTokens f = Parser $ \_ input -> [((), f input)]+----------------------------------------------------------------------------+-- | Retrieves read-only state from a Parser+askParser :: ParserT r token [] r+askParser = Parser $ \r input -> [(r, input)]+----------------------------------------------------------------------------+-- | Views the next token without consuming input+peek :: Parser a a+peek = Parser $ \_ tokens ->+ case tokens of+ [] -> []+ (x:xs) -> [(x, x:xs)]+----------------------------------------------------------------------------+-- | Parser combinator that always fails+errorOut :: errorToken -> ParserT r errorToken [] ()+errorOut x = Parser $ \_ _ -> [((),x)]+----------------------------------------------------------------------------+-- | Parser combinator that only succeeds if there are no more tokens.+endOfInput :: Parser a ()+endOfInput = guard . isNothing =<< optional anyToken+----------------------------------------------------------------------------
src/Miso/WebSocket.hs view
@@ -1,105 +1,204 @@+-----------------------------------------------------------------------------+{-# LANGUAGE TypeApplications #-} {-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-} ----------------------------------------------------------------------------- -- | -- Module : Miso.WebSocket--- Copyright : (C) 2016-2025 David M. Johnson+-- Copyright : (C) 2016-2026 David M. Johnson -- License : BSD3-style (see the file LICENSE) -- Maintainer : David M. Johnson <code@dmj.io> -- Stability : experimental -- Portability : non-portable ---------------------------------------------------------------------------- module Miso.WebSocket- ( -- * Types- WebSocket (..)- , URL (..)- , Protocols (..)+ ( -- *** t'WebSocket'+ connect+ , connectJSON+ , connectText+ , connectBLOB+ , connectArrayBuffer+ , sendText+ , sendJSON+ , sendBLOB+ , sendArrayBuffer+ , close+ , socketState+ -- *** Defaults+ , emptyWebSocket+ -- *** Types+ , WebSocket (..)+ , URL , SocketState (..) , CloseCode (..)- , WasClean (..)- , Reason (..)+ , Closed (..)+ , Payload (..)+ , Blob (..)+ , ArrayBuffer (..) ) where--import GHC.Generics-import Prelude hiding (map)-#ifdef ghcjs_HOST_OS-import GHCJS.Marshal-#endif--import Miso.String---- | WebSocket connection messages-data WebSocket action- = WebSocketMessage action- | WebSocketClose CloseCode WasClean Reason- | WebSocketOpen- | WebSocketError MisoString- deriving (Show, Eq)---- | URL of Websocket server-newtype URL = URL MisoString- deriving (Show, Eq)---- | Protocols for Websocket connection-newtype Protocols = Protocols [MisoString]- deriving (Show, Eq)---- | Wether or not the connection closed was done so cleanly-newtype WasClean = WasClean Bool deriving (Show, Eq)---- | Reason for closed connection-newtype Reason = Reason MisoString deriving (Show, Eq)---- | `SocketState` corresponding to current WebSocket connection-data SocketState- = CONNECTING -- ^ 0- | OPEN -- ^ 1- | CLOSING -- ^ 2- | CLOSED -- ^ 3- deriving (Show, Eq, Ord, Enum)---- | Code corresponding to a closed connection--- https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent-data CloseCode- = CLOSE_NORMAL- -- ^ 1000, Normal closure; the connection successfully completed whatever purpose for which it was created.- | CLOSE_GOING_AWAY- -- ^ 1001, The endpoint is going away, either because of a server failure or because the browser is navigating away from the page that opened the connection.- | CLOSE_PROTOCOL_ERROR- -- ^ 1002, The endpoint is terminating the connection due to a protocol error.- | CLOSE_UNSUPPORTED- -- ^ 1003, The connection is being terminated because the endpoint received data of a type it cannot accept (for example, a textonly endpoint received binary data).- | CLOSE_NO_STATUS- -- ^ 1005, Reserved. Indicates that no status code was provided even though one was expected.- | CLOSE_ABNORMAL- -- ^ 1006, Reserved. Used to indicate that a connection was closed abnormally (that is, with no close frame being sent) when a status code is expected.- | Unsupported_Data- -- ^ 1007, The endpoint is terminating the connection because a message was received that contained inconsistent data (e.g., nonUTF8 data within a text message).- | Policy_Violation- -- ^ 1008, The endpoint is terminating the connection because it received a message that violates its policy. This is a generic status code, used when codes 1003 and 1009 are not suitable.- | CLOSE_TOO_LARGE- -- ^ 1009, The endpoint is terminating the connection because a data frame was received that is too large.- | Missing_Extension- -- ^ 1010, The client is terminating the connection because it expected the server to negotiate one or more extension, but the server didn't.- | Internal_Error- -- ^ 1011, The server is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request.- | Service_Restart- -- ^ 1012, The server is terminating the connection because it is restarting.- | Try_Again_Later- -- ^ 1013, The server is terminating the connection due to a temporary condition, e.g. it is overloaded and is casting off some of its clients.- | TLS_Handshake- -- ^ 1015, Reserved. Indicates that the connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can't be verified).- | OtherCode Int- -- ^ OtherCode that is reserved and not in the range 0999- deriving (Show, Eq, Generic)--#ifdef ghcjs_HOST_OS--- Defined here to avoid an orphan instance-instance ToJSVal CloseCode-instance FromJSVal CloseCode-#endif+-----------------------------------------------------------------------------+import Miso.Effect+import Miso.JSON+import Miso.Runtime+import Miso.String (MisoString)+import Miso.FFI (Blob(..), ArrayBuffer(..))+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket>+--+-- Establishes a t'WebSocket' server that receives potentially multiple different t'Payload'.+--+-- It's more common to use 'connectJSON' or 'connectText'. But 'connect' can be used to received multiple+-- different kinds of data from a t'WebSocket' server.+--+connect+ :: FromJSON json+ => URL+ -- ^ URL endpoint for a t'WebSocket' connection+ -> (WebSocket -> action)+ -- ^ @onOpen@ callback w/ t'WebSocket' object for successful connection. t'WebSocket' is used here to send messages.+ -> (Closed -> action)+ -- ^ @onClosed@ method that is called when a t'WebSocket' connection has closed.+ -> (Payload json -> action)+ -- ^ @onMessage@ is a callback invoked when a message has been received from the t'WebSocket' server.+ -> (MisoString -> action)+ -- ^ Error message callback+ -> Effect parent model action+connect = websocketConnect+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket>+--+-- Establishes a t'WebSocket' server that assumes a JSON-encoded protocol.+--+connectJSON+ :: FromJSON json+ => URL+ -- ^ URL endpoint for a t'WebSocket' connection+ -> (WebSocket -> action)+ -- ^ @onOpen@ callback w/ t'WebSocket' object for successful connection. t'WebSocket' is used here to send messages.+ -> (Closed -> action)+ -- ^ @onClosed@ method that is called when a t'WebSocket' connection has closed.+ -> (json -> action)+ -- ^ @onMessage@ is a callback invoked when a JSON-encoded message has been received from the t'WebSocket' server.+ -> (MisoString -> action)+ -- ^ Error message callback+ -> Effect parent model action+connectJSON = websocketConnectJSON+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket>+--+-- Establishes a t'WebSocket' server that assumes a text-encoded protocol.+--+connectText+ :: URL+ -- ^ URL endpoint for a t'WebSocket' connection+ -> (WebSocket -> action)+ -- ^ @onOpen@ callback w/ t'WebSocket' object for successful connection. t'WebSocket' is used here to send messages.+ -> (Closed -> action)+ -- ^ @onClosed@ method that is called when a t'WebSocket' connection has closed.+ -> (MisoString -> action)+ -- ^ @onMessage@ is a callback invoked when a text-encoded message has been received from the t'WebSocket' server.+ -> (MisoString -> action)+ -- ^ Error message callback+ -> Effect parent model action+connectText = websocketConnectText+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket>+--+-- Establishes a t'WebSocket' server that assumes a binary-encoded protocol.+--+connectBLOB+ :: URL+ -- ^ URL endpoint for a t'WebSocket' connection+ -> (WebSocket -> action)+ -- ^ @onOpen@ callback w/ t'WebSocket' object for successful connection. t'WebSocket' is used here to send messages.+ -> (Closed -> action)+ -- ^ @onClosed@ method that is called when a t'WebSocket' connection has closed.+ -> (Blob -> action)+ -- ^ @onMessage@ is a callback invoked when a binary-encoded message has been received from the t'WebSocket' server.+ -> (MisoString -> action)+ -- ^ @onError@ callback+ -> Effect parent model action+connectBLOB = websocketConnectBLOB+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket>+--+-- Establishes a t'WebSocket' server that assumes an t'ArrayBuffer' protocol.+--+connectArrayBuffer+ :: URL+ -- ^ URL endpoint for a t'WebSocket' connection+ -> (WebSocket -> action)+ -- ^ @onOpen@ callback w/ t'WebSocket' object for successful connection. t'WebSocket' is used here to send messages.+ -> (Closed -> action)+ -- ^ @onClosed@ method that is called when a t'WebSocket' connection has closed.+ -> (ArrayBuffer -> action)+ -- ^ @onMessage@ is a callback invoked when an t'ArrayBuffer' message has been received from the t'WebSocket' server.+ -> (MisoString -> action)+ -- ^ @onError@ callback+ -> Effect parent model action+connectArrayBuffer = websocketConnectArrayBuffer+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send>+--+-- @+--+-- data Person = Person { name :: MisoString, age :: Int }+-- deriving (Show, Eq)+--+-- instance ToJSON Person where+-- toJSON (Person name age) = object [ "name" .= name, "age" .= age ]+--+-- test :: WebSocket -> Effect parent model action+-- test connection = do+-- sendJSON (connection :: WebSocket) (Person "alice" 42)+-- sendJSON (connection :: WebSocket) (Person "bob" 42)+--+-- @+--+sendJSON+ :: ToJSON json+ => WebSocket+ -- ^ t'WebSocket' descriptor required to send a message to the server.+ -> json+ -- ^ A JSON-encoded message+ -> Effect parent model action+sendJSON socket x = websocketSend socket (JSON x)+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send>+sendBLOB+ :: WebSocket+ -- ^ t'WebSocket' descriptor required to send a message to the server.+ -> Blob+ -- ^ An t'Blob' payload to send to the t'WebSocket' server+ -> Effect parent model action+sendBLOB socket x = websocketSend @() socket (blob x)+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send>+sendArrayBuffer+ :: WebSocket+ -- ^ t'WebSocket' descriptor required to send a message to the server.+ -> ArrayBuffer+ -- ^ An t'ArrayBuffer' payload to send to the t'WebSocket' server+ -> Effect parent model action+sendArrayBuffer socket x = websocketSend @() socket (arrayBuffer x)+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send>+sendText+ :: WebSocket+ -- ^ t'WebSocket' descriptor required to send a message to the server.+ -> MisoString+ -- ^ A text payload to send to t'WebSocket' server+ -> Effect parent model action+sendText socket x = websocketSend @() socket (TEXT x)+-----------------------------------------------------------------------------+-- | <https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close>+--+-- It is very important to close the t'WebSocket', otherwise leaks can occur.+--+-- 'close' is a no-op if invoked multiple times.+--+close+ :: WebSocket+ -- ^ t'WebSocket' descriptor required to close the socket on the server.+ -> Effect parent model action+close = websocketClose+-----------------------------------------------------------------------------
− tests/Main.hs
@@ -1,178 +0,0 @@-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE NamedFieldPuns #-}-module Main where--import Control.Exception hiding (assert)-import Control.Monad-import Control.Monad.IO.Class (liftIO)-import Control.Monad.Trans.State-import Data.Aeson hiding (Result(..))-import qualified Data.HashMap.Strict as H-import Data.Scientific-import qualified Data.Vector as V-import Debug.Trace-import GHCJS.Marshal-import GHCJS.Types-import qualified JavaScript.Object.Internal as OI-import System.IO.Unsafe-import Test.QuickCheck hiding (total)-import Test.QuickCheck.Instances-import Test.QuickCheck.Monadic--import Miso--instance Arbitrary Value where- arbitrary = sized sizedArbitraryValue--sizedArbitraryValue :: Int -> Gen Value-sizedArbitraryValue n- | n <= 0 = oneof [pure Null, bool, number, string]- | otherwise = resize n' $ oneof [pure Null, bool, string, number, array, object']- where- n' = n `div` 2- bool = Bool <$> arbitrary- number = Number <$> arbitrary- string = String <$> arbitrary- array = Array <$> arbitrary- object' = Object <$> arbitrary--compareValue :: Value -> Value -> Bool-compareValue (Object x) (Object y) = and $ zipWith compareValue (H.elems x) (H.elems y)-compareValue (Array x) (Array y) = and $ zipWith compareValue (V.toList x) (V.toList y)-compareValue (String x) (String y) = x == y-compareValue (Bool x) (Bool y) = x == y-compareValue Null Null = True-compareValue (Number x) (Number y) = closeEnough x y-compareValue _ _ = False--closeEnough x y- = let d = max (abs x) (abs y)- relDiff = if (d == 0.0) then d else abs (x - y) / d- in relDiff <= 0.00001--main :: IO ()-main = runTests $ do- storageTests- roundTripJSVal--storageTests :: TestM ()-storageTests = do- it "should write to and read from local storage" $ do- let obj = object [ "foo" .= ("bar" :: String) ]- setLocalStorage "foo" obj- Right r <- getLocalStorage "foo"- r `shouldBe` obj- it "should write to and read from session storage" $ do- let obj = object [ "foo" .= ("bar" :: String) ]- setSessionStorage "foo" obj- Right r <- getLocalStorage "foo"- r `shouldBe` obj--roundTripJSVal :: TestM ()-roundTripJSVal =- it "Should round trip JSVal" $ do- propTest iso_prop--roundTrip- :: Value- -> IO Bool-roundTrip x = do- Just y <- fromJSVal =<< toJSVal x- pure $ compareValue x y == True--iso_prop :: Value -> Property-iso_prop = monadicIO . run . roundTrip--propTest :: Testable prop => prop -> IO (Bool, String)-propTest prop = do- r <- flip quickCheckWithResult prop stdArgs { chatty = False }- pure $ case r of- Success { output = o } -> (True, o)- GaveUp { output = o } -> (False, o)- Failure { output = o } -> (False, o)- NoExpectedFailure { output = o } -> (False, o)--foreign import javascript unsafe "window.global_test_results = $1;"- writeToGlobalObject :: JSVal -> IO ()--runTests :: TestM () -> IO ()-runTests t = do- results <- toJSVal =<< toResult <$> execStateT t []- consoleLogJSVal results- writeToGlobalObject results- where- toResult :: [Test] -> TestResult- toResult xs = TestResult failed' passed' total' duration' xs- where- passed' = length (filter result xs)- failed' = length (filter (not . result) xs)- total' = length xs- duration' = sum (map duration xs)--instance ToJSVal TestResult where- toJSVal t = do- o@(OI.Object j) <- OI.create- set "passed" (passed t) o- set "failed" (failed t) o- set "total" (total t) o- set "duration" (duration' t) o- set "tests" (tests t) o- pure j--instance ToJSVal Test where- toJSVal t = do- o@(OI.Object j) <- OI.create- set "name" (name t) o- set "result" (result t) o- set "message" (message t) o- set "duration" (duration t) o- pure j--it :: String -> IO (Bool, String) -> TestM ()-it name test = do- (result, msg, time) <- liftIO $ (do- ((x,msg),t) <- clock test- pure (x,msg,t))- `catch` (\(e :: SomeException) ->- pure (False, show e, 0))- modify (Test name result msg time:)--data TestResult- = TestResult- { failed :: Int- , passed :: Int- , total :: Int- , duration' :: Double- , tests :: [Test]- } deriving (Show, Eq)--data Test- = Test- { name :: String- , result :: Bool- , message :: String- , duration :: Double- } deriving (Show, Eq)--type TestM a = StateT [Test] IO a--shouldBe :: (Show a, Eq a, Applicative f) => a -> a -> f (Bool, String)-shouldBe x y =- pure $- if x == y- then (True, mempty)- else (False, "Expecting: " ++ show y ++ " but got: " ++ show x)--infix 0 `shouldBe`---- | Measure in seconds-clock :: IO a -> IO (a, Double)-clock action = do- start <- now- x <- action- stop <- now- pure (x, (stop - start) / 1000)
− text-src/Miso/String.hs
@@ -1,103 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE OverloadedStrings #-}--------------------------------------------------------------------------------- |--- Module : Miso.String--- Copyright : (C) 2016-2025 David M. Johnson--- License : BSD3-style (see the file LICENSE)--- Maintainer : David M. Johnson <code@dmj.io>--- Stability : experimental--- Portability : non-portable------------------------------------------------------------------------------module Miso.String- ( ToMisoString (..)- , FromMisoString (..)- , fromMisoString- , MisoString- , module S- , ms- ) where--import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as BL-import Data.Monoid as S-import Data.JSString-import Data.JSString.Text-#if MIN_VERSION_text(2,1,2)-import Data.Text as S hiding (show)-#else-import Data.Text as S-#endif -import qualified Data.Text as T-import qualified Data.Text.Encoding as T-import qualified Data.Text.Lazy as LT-import qualified Data.Text.Lazy.Encoding as LT-import Text.Read(readEither)-import Prelude as P---- | String type swappable based on compiler-type MisoString = Text---- | Convenience class for creating `MisoString` from other string-like types-class ToMisoString str where- toMisoString :: str -> MisoString---- | Class from safely parsing 'MisoString'-class FromMisoString t where- -- -- | Parses a `MisoString`- fromMisoStringEither :: MisoString -> Either String t---- | Parses a `MisoString`, throws an error when decoding--- fails. Use `fromMisoStringEither` for as a safe alternative.-fromMisoString :: FromMisoString a => MisoString -> a-fromMisoString s = case fromMisoStringEither s of- Left err -> error err- Right x -> x---- | Convenience function, shorthand for `toMisoString`-ms :: ToMisoString str => str -> MisoString-ms = toMisoString--instance ToMisoString MisoString where- toMisoString = id-instance ToMisoString String where- toMisoString = T.pack-instance ToMisoString LT.Text where- toMisoString = LT.toStrict-instance ToMisoString JSString where- toMisoString = textFromJSString-instance ToMisoString B.ByteString where- toMisoString = toMisoString . T.decodeUtf8-instance ToMisoString BL.ByteString where- toMisoString = toMisoString . LT.decodeUtf8-instance ToMisoString Float where- toMisoString = T.pack . P.show-instance ToMisoString Double where- toMisoString = T.pack . P.show-instance ToMisoString Int where- toMisoString = T.pack . P.show-instance ToMisoString Word where- toMisoString = T.pack . P.show--instance FromMisoString MisoString where- fromMisoStringEither = Right-instance FromMisoString String where- fromMisoStringEither = Right . T.unpack-instance FromMisoString LT.Text where- fromMisoStringEither = Right . LT.fromStrict-instance FromMisoString JSString where- fromMisoStringEither = Right . textToJSString-instance FromMisoString B.ByteString where- fromMisoStringEither = fmap T.encodeUtf8 . fromMisoStringEither-instance FromMisoString BL.ByteString where- fromMisoStringEither = fmap LT.encodeUtf8 . fromMisoStringEither-instance FromMisoString Float where- fromMisoStringEither = readEither . T.unpack-instance FromMisoString Double where- fromMisoStringEither = readEither . T.unpack-instance FromMisoString Int where- fromMisoStringEither = readEither . T.unpack-instance FromMisoString Word where- fromMisoStringEither = readEither . T.unpack