From ebfc9126fde35867b49c1ec4a60a65dd5191442c Mon Sep 17 00:00:00 2001 From: lue-bird Date: Thu, 28 Mar 2024 23:12:42 +0100 Subject: [PATCH] preview docs update --- docs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs.json b/docs.json index 3b6884c..0411b54 100644 --- a/docs.json +++ b/docs.json @@ -1 +1 @@ -[{"name":"Web","comment":" A state-interface program that can run in the browser\n\n@docs ProgramConfig, program, Program\n\nYou can also [embed](#embed) a state-interface program as part of an existing app that uses The Elm Architecture\n\n\n# interfaces\n\n@docs Interface, interfaceBatch, interfaceNone, interfaceFutureMap\n\n\n## DOM\n\nTypes used by [`Web.Dom`](Web-Dom)\n\n@docs DomNode, DomElement, DomElementVisibilityAlignment, DefaultActionHandling\n\n\n## Audio\n\nTypes used by [`Web.Audio`](Web-Audio)\n\n@docs Audio, AudioSource, AudioSourceLoadError, AudioProcessing, AudioParameterTimeline, EditAudioDiff\n\n\n## HTTP\n\nTypes used by [`Web.Http`](Web-Http)\n\n@docs HttpRequest, HttpBody, HttpExpect, HttpError, HttpMetadata\n\n\n## socket\n\nTypes used by [`Web.Socket`](Web-Socket)\n\n@docs SocketConnectionEvent, SocketId\n\n\n## geo location\n\nTypes used by [`Web.GeoLocation`](Web-GeoLocation)\n\n@docs GeoLocation\n\n\n## gamepads\n\nTypes used by [`Web.Gamepads`](Web-Gamepads)\n\n@docs Gamepad, GamepadButton\n\n\n## notification\n\nTypes used by [`Web.Notification`](Web-Notification)\n\n@docs NotificationClicked\n\n\n## window\n\nTypes used by [`Web.Window`](Web-Window)\n\n@docs WindowVisibility\n\n\n## embed\n\nIf you just want to replace a part of your elm app with this architecture. Make sure to wire in all 3:\n\n@docs programInit, programUpdate, programSubscriptions\n\nUnder the hood, [`Web.program`](Web#program) is then defined as just\n\n program config =\n Platform.worker\n { init = \\() -> Web.programInit yourAppConfig\n , update = Web.programUpdate yourAppConfig\n , subscriptions = Web.programSubscriptions yourAppConfig\n }\n\n\n## internals, safe to ignore for users\n\n@docs ProgramState, ProgramEvent\n@docs InterfaceSingle, InterfaceSingleWithFuture, InterfaceSingleRequest, InterfaceSingleListen, InterfaceSingleWithoutFuture\n@docs interfaceDiffs, findInterfaceAssociatedWithDiffComingBack, interfaceFutureJsonDecoder, InterfaceDiff, InterfaceWithFutureDiff, InterfaceWithoutFutureDiff, EditDomDiff, ReplacementInEditDomDiff, InterfaceSingleRequestId, InterfaceSingleListenId, DomElementId, DomNodeId, HttpRequestId, HttpExpectId\n\n","unions":[{"name":"AudioProcessing","comment":" A single effect filter applied to an [`Audio`](#Audio)\n","args":[],"cases":[["AudioLinearConvolution",["{ sourceUrl : String.String }"]],["AudioLowpass",["{ cutoffFrequency : Web.AudioParameterTimeline }"]],["AudioHighpass",["{ cutoffFrequency : Web.AudioParameterTimeline }"]]]},{"name":"AudioSourceLoadError","comment":" These are possible errors we can get when loading an audio source file.\n\n - `AudioSourceLoadDecodeError`: This means we got the data but we couldn't decode it. One likely reason for this is that your url points to the wrong place and you're trying to decode a 404 page instead.\n - `AudioSourceLoadNetworkError`: We couldn't reach the url. Either it's some kind of CORS issue, the server is down, or you're disconnected from the internet.\n - `AudioSourceLoadUnknownError`: the audio source didn't load for a reason I'm not aware of. If this occurs in your app, [open an issue](https://github.com/lue-bird/elm-state-interface/issues/new) with the reason string so a new variant can be added for this\n\n","args":[],"cases":[["AudioSourceLoadDecodeError",[]],["AudioSourceLoadNetworkError",[]],["AudioSourceLoadUnknownError",["String.String"]]]},{"name":"DefaultActionHandling","comment":" Setting for a listen [`Web.Dom.Modifier`](Web-Dom#Modifier) to keep or overwrite the browsers default action\n","args":[],"cases":[["DefaultActionPrevent",[]],["DefaultActionExecute",[]]]},{"name":"DomElementVisibilityAlignment","comment":" What part of the [`DomElement`](Web#DomElement) should be visible\n\n - `DomElementStart`: mostly for text to read\n - `DomElementEnd`: mostly for text to write\n - `DomElementCenter`: mostly for images\n\n","args":[],"cases":[["DomElementStart",[]],["DomElementEnd",[]],["DomElementCenter",[]]]},{"name":"DomNode","comment":" Plain text or a [`DomElement`](#DomElement) for use in an [`Interface`](#Interface).\n","args":["future"],"cases":[["DomText",["String.String"]],["DomElement",["Web.DomElement future"]]]},{"name":"DomNodeId","comment":" Safe to ignore. Identifier for a [`DomNode`](#DomNode)\n","args":[],"cases":[["DomTextId",["String.String"]],["DomElementId",["Web.DomElementId"]]]},{"name":"EditAudioDiff","comment":" What parts of an [`Audio`](#Audio) are replaced\n","args":[],"cases":[["ReplacementAudioVolume",["Web.AudioParameterTimeline"]],["ReplacementAudioSpeed",["Web.AudioParameterTimeline"]],["ReplacementAudioStereoPan",["Web.AudioParameterTimeline"]],["ReplacementAudioProcessing",["List.List Web.AudioProcessing"]]]},{"name":"GamepadButton","comment":" Buttons are either held down with an optional value between 0 and 1 to measure how hard,\nor they are released with an optional detection of touch which defaults to false.\n","args":[],"cases":[["GamepadButtonPressed",["{ firmnessPercentage : Basics.Float }"]],["GamepadButtonReleased",["{ isTouched : Basics.Bool }"]]]},{"name":"HttpBody","comment":" Data send in your http request.\n\n - `HttpBodyEmpty`: Create an empty body for your request.\n This is useful for `GET` requests and `POST` requests where you are not sending any data.\n\n - `HttpBodyString`: Put a `String` in the body of your request. Defining `Web.Http.jsonBody` looks like this:\n\n import Json.Encode\n\n jsonBody : Json.Encode.Value -> Web.HttpBody\n jsonBody value =\n Web.HttpBodyString \"application/json\" (Json.Encode.encode 0 value)\n\n The first argument is a [MIME type](https://en.wikipedia.org/wiki/Media_type) of the body.\n\n - `HttpBodyUnsignedInt8s` is pretty much the same as `HttpBodyString` but for [`Bytes`](https://dark.elm.dmy.fr/packages/elm/bytes/latest/),\n see [`Web.Http.bodyBytes`](Web-Http#bodyBytes)\n\n","args":[],"cases":[["HttpBodyEmpty",[]],["HttpBodyString",["{ mimeType : String.String, content : String.String }"]],["HttpBodyUnsignedInt8s",["{ mimeType : String.String, content : List.List Basics.Int }"]]]},{"name":"HttpError","comment":" A Request can fail in a couple ways:\n\n - `BadUrl` means you did not provide a valid URL.\n - `Timeout` means it took too long to get a response.\n - `NetworkError` means the user turned off their wifi, went in a cave, etc.\n - `BadStatus` means you got a response back, but the status code indicates failure. Contains:\n - The response `Metadata`.\n - The raw response body as a `Json.Decode.Value`.\n\n","args":[],"cases":[["HttpBadUrl",["String.String"]],["HttpTimeout",[]],["HttpNetworkError",[]],["HttpBadStatus",["{ metadata : Web.HttpMetadata, body : Json.Decode.Value }"]]]},{"name":"HttpExpect","comment":" Describe what you expect to be returned in an http response body.\n","args":["future"],"cases":[["HttpExpectString",["Result.Result Web.HttpError String.String -> future"]],["HttpExpectBytes",["Result.Result Web.HttpError Bytes.Bytes -> future"]],["HttpExpectWhatever",["Result.Result Web.HttpError () -> future"]]]},{"name":"HttpExpectId","comment":" Safe to ignore. Identifier for an [`HttpExpect`](#HttpExpect)\n","args":[],"cases":[["IdHttpExpectString",[]],["IdHttpExpectBytes",[]],["IdHttpExpectWhatever",[]]]},{"name":"InterfaceDiff","comment":" Safe to ignore. Individual messages to js. Also used to identify responses with the same part in the interface\n","args":[],"cases":[["InterfaceWithFutureDiff",["Web.InterfaceWithFutureDiff"]],["InterfaceWithoutFutureDiff",["Web.InterfaceWithoutFutureDiff"]]]},{"name":"InterfaceSingle","comment":" A \"non-batched\" [`Interface`](#Interface).\nTo create one, use the helpers in `Web.Time`, `.Dom`, `.Http` etc.\n","args":["future"],"cases":[["InterfaceWithFuture",["Web.InterfaceSingleWithFuture future"]],["InterfaceWithoutFuture",["Web.InterfaceSingleWithoutFuture"]]]},{"name":"InterfaceSingleListen","comment":" An [`InterfaceSingleWithFuture`](#InterfaceSingleWithFuture) that will possibly notify elm multiple times in the future.\n","args":["future"],"cases":[["WindowEventListen",["{ eventName : String.String, on : Json.Decode.Decoder future }"]],["WindowVisibilityChangeListen",["Web.WindowVisibility -> future"]],["WindowAnimationFrameListen",["Time.Posix -> future"]],["WindowPreferredLanguagesChangeListen",["List.List String.String -> future"]],["DocumentEventListen",["{ eventName : String.String, on : Json.Decode.Decoder future }"]],["TimePeriodicallyListen",["{ intervalDurationMilliSeconds : Basics.Int, on : Time.Posix -> future }"]],["SocketMessageListen",["{ id : Web.SocketId, on : String.String -> future }"]],["LocalStorageRemoveOnADifferentTabListen",["{ key : String.String, on : AppUrl.AppUrl -> future }"]],["LocalStorageSetOnADifferentTabListen",["{ key : String.String, on : { appUrl : AppUrl.AppUrl, oldValue : Maybe.Maybe String.String, newValue : String.String } -> future }"]],["GeoLocationChangeListen",["Web.GeoLocation -> future"]],["GamepadsChangeListen",["Dict.Dict Basics.Int Web.Gamepad -> future"]]]},{"name":"InterfaceSingleListenId","comment":" Safe to ignore. Possible identifier for an interface single that can send back values to elm\nat multiple times in the future\n","args":[],"cases":[["IdWindowEventListen",["String.String"]],["IdWindowVisibilityChangeListen",[]],["IdWindowAnimationFrameListen",[]],["IdWindowPreferredLanguagesChangeListen",[]],["IdDocumentEventListen",["String.String"]],["IdTimePeriodicallyListen",["{ milliSeconds : Basics.Int }"]],["IdSocketMessageListen",["Web.SocketId"]],["IdLocalStorageRemoveOnADifferentTabListen",["{ key : String.String }"]],["IdLocalStorageSetOnADifferentTabListen",["{ key : String.String }"]],["IdGeoLocationChangeListen",[]],["IdGamepadsChangeListen",[]]]},{"name":"InterfaceSingleRequest","comment":" An [`InterfaceSingleWithFuture`](#InterfaceSingleWithFuture) that will elm only once in the future.\n","args":["future"],"cases":[["TimePosixRequest",["Time.Posix -> future"]],["TimezoneOffsetRequest",["Basics.Int -> future"]],["TimezoneNameRequest",["Time.ZoneName -> future"]],["RandomUnsignedInt32sRequest",["{ count : Basics.Int, on : List.List Basics.Int -> future }"]],["WindowSizeRequest",["{ width : Basics.Int, height : Basics.Int } -> future"]],["WindowPreferredLanguagesRequest",["List.List String.String -> future"]],["NavigationUrlRequest",["AppUrl.AppUrl -> future"]],["HttpRequest",["Web.HttpRequest future"]],["ClipboardRequest",["String.String -> future"]],["LocalStorageRequest",["{ key : String.String, on : Maybe.Maybe String.String -> future }"]],["GeoLocationRequest",["Web.GeoLocation -> future"]],["GamepadsRequest",["Dict.Dict Basics.Int Web.Gamepad -> future"]]]},{"name":"InterfaceSingleRequestId","comment":" Safe to ignore. Possible identifier for an interface single that can send back values to elm\nonly once in the future\n","args":[],"cases":[["IdTimePosixRequest",[]],["IdTimezoneOffsetRequest",[]],["IdTimezoneNameRequest",[]],["IdRandomUnsignedInt32sRequest",["Basics.Int"]],["IdWindowSizeRequest",[]],["IdWindowPreferredLanguagesRequest",[]],["IdNavigationUrlRequest",[]],["IdHttpRequest",["Web.HttpRequestId"]],["IdClipboardRequest",[]],["IdLocalStorageRequest",["{ key : String.String }"]],["IdGeoLocationRequest",[]],["IdGamepadsRequest",[]]]},{"name":"InterfaceSingleWithFuture","comment":" An [`InterfaceSingle`](#InterfaceSingle) that will notify elm some time in the future.\n","args":["future"],"cases":[["DomNodeRender",["Web.DomNode future"]],["AudioSourceLoad",["{ url : String.String, on : Result.Result Web.AudioSourceLoadError Web.AudioSource -> future }"]],["SocketConnect",["{ address : String.String, on : Web.SocketConnectionEvent -> future }"]],["NotificationShow",["{ id : String.String, message : String.String, details : String.String, on : Web.NotificationClicked -> future }"]],["Request",["Web.InterfaceSingleRequest future"]],["Listen",["Web.InterfaceSingleListen future"]]]},{"name":"InterfaceSingleWithoutFuture","comment":" An [`InterfaceSingle`](#InterfaceSingle) that will never notify elm\n","args":[],"cases":[["DocumentTitleReplaceBy",["String.String"]],["DocumentAuthorSet",["String.String"]],["DocumentKeywordsSet",["List.List String.String"]],["DocumentDescriptionSet",["String.String"]],["ConsoleLog",["String.String"]],["ConsoleWarn",["String.String"]],["ConsoleError",["String.String"]],["NavigationReplaceUrl",["AppUrl.AppUrl"]],["NavigationPushUrl",["AppUrl.AppUrl"]],["NavigationGo",["Basics.Int"]],["NavigationLoad",["String.String"]],["NavigationReload",[]],["FileDownloadUnsignedInt8s",["{ mimeType : String.String, name : String.String, content : List.List Basics.Int }"]],["ClipboardReplaceBy",["String.String"]],["AudioPlay",["Web.Audio"]],["SocketMessage",["{ id : Web.SocketId, data : String.String }"]],["SocketDisconnect",["Web.SocketId"]],["LocalStorageSet",["{ key : String.String, value : Maybe.Maybe String.String }"]],["NotificationAskForPermission",[]]]},{"name":"InterfaceWithFutureDiff","comment":" Actions that will notify elm some time in the future\n","args":[],"cases":[["EditDom",["Web.EditDomDiff"]],["AddSocketConnect",["{ address : String.String }"]],["AddAudioSourceLoad",["String.String"]],["AddNotificationShow",["{ id : String.String, message : String.String, details : String.String }"]],["AddRequest",["Web.InterfaceSingleRequestId"]],["AddListen",["Web.InterfaceSingleListenId"]]]},{"name":"InterfaceWithoutFutureDiff","comment":" Actions that will never notify elm again\n","args":[],"cases":[["Add",["Web.InterfaceSingleWithoutFuture"]],["EditAudio",["{ url : String.String, startTime : Time.Posix, replacement : Web.EditAudioDiff }"]],["RemoveHttpRequest",["Web.HttpRequestId"]],["RemoveDom",[]],["RemoveSocketConnect",["{ address : String.String }"]],["RemoveAudio",["{ url : String.String, startTime : Time.Posix }"]],["EditNotification",["{ id : String.String, message : String.String, details : String.String }"]],["RemoveNotificationShow",["{ message : String.String, details : String.String }"]],["RemoveListen",["Web.InterfaceSingleListenId"]]]},{"name":"NotificationClicked","comment":" The user clicked a displayed notification,\nmoving the focus to our page\n","args":[],"cases":[["NotificationClicked",[]]]},{"name":"ProgramEvent","comment":" Ignore the specific variants, this is just exposed so can\nfor example simulate it more easily in tests, add a debugger etc.\n\nA [`Web.program`](#program) would have this type\n\n main : Platform.Program () (Web.State YourState) (Web.Event YourState)\n main =\n Web.toProgram ...\n\nIn practice, please use [`Web.Program YourState`](#Program)\n\n","args":["appState"],"cases":[["InterfaceDiffFailedToDecode",["Json.Decode.Error"]],["InterfaceEventDataFailedToDecode",["Json.Decode.Error"]],["InterfaceEventIgnored",[]],["AppEventToNewAppState",["appState"]]]},{"name":"ProgramState","comment":" Ignore the specific fields, this is just exposed so can\nfor example simulate it more easily in tests, add a debugger etc.\n\nA [`Web.program`](#program) would have this type\n\n main : Platform.Program () (Web.State YourState) (Web.Event YourState)\n main =\n Web.toProgram ...\n\nIn practice, please use [`Web.Program YourState`](#Program)\n\n","args":["appState"],"cases":[["State",["{ interface : FastDict.Dict (List.List String.String) (Web.InterfaceSingle appState), appState : appState }"]]]},{"name":"ReplacementInEditDomDiff","comment":" What parts of a node are replaced. Either all modifiers of a certain kind or the whole node\n","args":[],"cases":[["ReplacementDomNode",["Web.DomNodeId"]],["ReplacementDomElementStyles",["Dict.Dict String.String String.String"]],["ReplacementDomElementAttributes",["Dict.Dict String.String String.String"]],["ReplacementDomElementAttributesNamespaced",["Dict.Dict ( String.String, String.String ) String.String"]],["ReplacementDomElementScrollToPosition",["Maybe.Maybe { fromLeft : Basics.Float, fromTop : Basics.Float }"]],["ReplacementDomElementScrollToShow",["Maybe.Maybe { x : Web.DomElementVisibilityAlignment, y : Web.DomElementVisibilityAlignment }"]],["ReplacementDomElementScrollPositionRequest",[]],["ReplacementDomElementEventListens",["Dict.Dict String.String Web.DefaultActionHandling"]]]},{"name":"SocketConnectionEvent","comment":" An indication that connection has changed\nafter having initiated [`Web.Socket.connectTo`](Web-Socket#connectTo).\n\n - `SocketConnected`: connection has been opened. Gives access to a [`Web.SocketId`](#SocketId)\n - `SocketDisconnected`: connection has been closed with\n - the close `code` sent by the server\n - The `reason` indicating why the server closed the connection, specific to the particular server and sub-protocol\n\n","args":[],"cases":[["SocketConnected",["Web.SocketId"]],["SocketDisconnected",["{ code : Basics.Int, reason : String.String }"]]]},{"name":"SocketId","comment":" Identifier for a [`Web.Socket`](Web-Socket) that can be used to [communicate](Web-Socket#communicate)\n","args":[],"cases":[["SocketId",["Basics.Int"]]]},{"name":"WindowVisibility","comment":" The visibility to the user\n\n - `WindowHidden`: the user has navigated to a new page, switched tabs, closed the tab, minimized or closed the browser, or, on mobile, switched from the browser to a different app\n - `WindowShown` otherwise\n\n","args":[],"cases":[["WindowShown",[]],["WindowHidden",[]]]}],"aliases":[{"name":"Audio","comment":" Some kind of sound we want to play. To create `Audio`, start with [`Web.Audio.fromSource`](Web-Audio#fromSource)\n","args":[],"type":"RecordWithoutConstructorFunction.RecordWithoutConstructorFunction { url : String.String, startTime : Time.Posix, volume : Web.AudioParameterTimeline, speed : Web.AudioParameterTimeline, stereoPan : Web.AudioParameterTimeline, processingLastToFirst : List.List Web.AudioProcessing }"},{"name":"AudioParameterTimeline","comment":" defining how loud a sound should be at any point in time\n","args":[],"type":"{ startValue : Basics.Float, keyFrames : List.List { time : Time.Posix, value : Basics.Float } }"},{"name":"AudioSource","comment":" Audio data we can use to play sounds.\nUse [`Web.Audio.sourceLoad`](Web-Audio#sourceLoad) to fetch an [`AudioSource`](#AudioSource).\n\nYou can also use the contained source `duration`, for example to find fade-out times or to create a loop:\n\n audioLoop : AudioSource -> Time.Posix -> Time.Posix -> Audio\n audioLoop source initialTime lastTick =\n Web.Audio.fromSource source\n (Duration.addTo\n initialTime\n (source.duration\n |> Quantity.multiplyBy\n (((Duration.from initialTime lastTick |> Duration.inSeconds)\n / (source.duration |> Duration.inSeconds)\n )\n |> floor\n |> toFloat\n )\n )\n )\n\n","args":[],"type":"RecordWithoutConstructorFunction.RecordWithoutConstructorFunction { url : String.String, duration : Duration.Duration }"},{"name":"DomElement","comment":" A tagged DOM node that can itself contain child [node](#DomNode)s\n","args":["future"],"type":"RecordWithoutConstructorFunction.RecordWithoutConstructorFunction { namespace : Maybe.Maybe String.String, tag : String.String, styles : Dict.Dict String.String String.String, attributes : Dict.Dict String.String String.String, attributesNamespaced : Dict.Dict ( String.String, String.String ) String.String, scrollToPosition : Maybe.Maybe { fromLeft : Basics.Float, fromTop : Basics.Float }, scrollToShow : Maybe.Maybe { x : Web.DomElementVisibilityAlignment, y : Web.DomElementVisibilityAlignment }, scrollPositionRequest : Maybe.Maybe ({ fromLeft : Basics.Float, fromTop : Basics.Float } -> future), eventListens : Dict.Dict String.String { on : Json.Decode.Value -> future, defaultActionHandling : Web.DefaultActionHandling }, subs : Array.Array (Web.DomNode future) }"},{"name":"DomElementId","comment":" Safe to ignore. Identifier for a [`DomElement`](#DomElement)\n","args":[],"type":"RecordWithoutConstructorFunction.RecordWithoutConstructorFunction { namespace : Maybe.Maybe String.String, tag : String.String, styles : Dict.Dict String.String String.String, attributes : Dict.Dict String.String String.String, attributesNamespaced : Dict.Dict ( String.String, String.String ) String.String, scrollToPosition : Maybe.Maybe { fromLeft : Basics.Float, fromTop : Basics.Float }, scrollToShow : Maybe.Maybe { x : Web.DomElementVisibilityAlignment, y : Web.DomElementVisibilityAlignment }, scrollPositionRequest : Basics.Bool, eventListens : Dict.Dict String.String Web.DefaultActionHandling, subs : Array.Array Web.DomNodeId }"},{"name":"EditDomDiff","comment":" Change the current node at a given path using a given [`ReplacementInEditDomDiff`](#ReplacementInEditDomDiff)\n","args":[],"type":"RecordWithoutConstructorFunction.RecordWithoutConstructorFunction { path : List.List Basics.Int, replacement : Web.ReplacementInEditDomDiff }"},{"name":"Gamepad","comment":" Controller information on button presses, thumbstick positions etc.\n\n - `primaryButton`: The most common action like \"enter\"/\"confirm\" or jump\n\n - `secondaryButton`: Usually \"cancel\"/\"skip\" or a common ability like duck/sneak, drop or heal\n\n - `tertiaryButton`: common-ish ability like consume, interact, reload or an ultimate power\n\n - `quaternaryButton`: less common action like quick menu or mode switch\n\n - `leftBumperButton`, `rightBumperButton`: The top row of smaller buttons on the side opposite of you, sometimes called shoulder buttons.\n Often used for alternative menu actions like slot switching or quick map\n\n - `leftTriggerButton`, `rightTriggerButton`: The bottom row of larger buttons on the side opposite of you.\n Often used for holdable abilities like sliding or dashing\n\n - `selectButton`: Usually opens an in-world menu with for example inventory, lore, ability overview or a map\n\n - `startButton`: Usually pauses the game and opens a menu with options like settings and quit\n\n - `leftThumbstickButton`, `rightThumbstickButton`: Not all gamepads have these, so they often either double existing actions like \"confirm\"\n or perform actions that are only very rarely helpful, like hiding ui elements or making a screenshot\n\n - `upButton`, `downBottom`, `leftButton`, `rightButton`: exactly one step in a direction, usually in a (quick) menu/inventory\n\n - \\`homeButton: Usually turns the gamepad on/off, or changes the state of the game\n\n - `touchpadButton`: Not present on most gamepads. While the touchpad is often used for controlling the mouse, it can also be used as a simple button\n\n - `thumbstickLeft`, `thumbstickRight`: Those wiggly that can be moved in any direction by any amount.\n They are provided as `x, y` signed percentages\n\n - `kindId`: some information about the gamepad, usually containing the USB vendor, product id of the gamepad\n and the name of the gamepad as provided by the driver. See [mdn](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad/id)\n\n You can use this information to for example determine how to show controls\n\n - `buttonsAdditional`, `thumbsticksAdditional`: Maybe you have a weird gamepad with 3 thumbsticks? These might help 🤷\n\nImplementation note:\nAs you know, gamepad layouts differ between models.\nFor most of them, we're able to map them to the buttons and thumbsticks above.\nIf you experience issues with some model, [open an issue]()\n\n","args":[],"type":"RecordWithoutConstructorFunction.RecordWithoutConstructorFunction { primaryButton : Web.GamepadButton, secondaryButton : Web.GamepadButton, tertiaryButton : Web.GamepadButton, quaternaryButton : Web.GamepadButton, leftBumperButton : Web.GamepadButton, rightBumperButton : Web.GamepadButton, leftTriggerButton : Web.GamepadButton, rightTriggerButton : Web.GamepadButton, selectButton : Web.GamepadButton, startButton : Web.GamepadButton, leftThumbstickButton : Web.GamepadButton, rightThumbstickButton : Web.GamepadButton, upButton : Web.GamepadButton, downButton : Web.GamepadButton, leftButton : Web.GamepadButton, rightButton : Web.GamepadButton, homeButton : Web.GamepadButton, touchpadButton : Web.GamepadButton, additionalButtons : List.List Web.GamepadButton, kindId : String.String, thumbstickLeft : { x : Basics.Float, y : Basics.Float }, thumbstickRight : { x : Basics.Float, y : Basics.Float }, thumbsticksAdditional : List.List { x : Basics.Float, y : Basics.Float } }"},{"name":"GeoLocation","comment":" Position and (if available) altitude of the device on Earth, as well as the accuracy with which these properties are calculated.\nThe geographic position information is provided in terms of World Geodetic System coordinates (WGS84).\n\nDevice movement direction and speed might also be provided.\n\n[`Length`](https://dark.elm.dmy.fr/packages/ianmackenzie/elm-units/latest/Length),\n[`Angle`](https://dark.elm.dmy.fr/packages/ianmackenzie/elm-units/latest/Angle) and\n[`Speed`](https://dark.elm.dmy.fr/packages/ianmackenzie/elm-units/latest/Speed)\nare from `ianmackenzie/elm-units`\n\n","args":[],"type":"RecordWithoutConstructorFunction.RecordWithoutConstructorFunction { latitudeInDecimalDegrees : Basics.Float, longitudeInDecimalDegrees : Basics.Float, latitudeLongitudeAccuracy : Maybe.Maybe Length.Length, altitudeAboveNominalSeaLevel : Maybe.Maybe Length.Length, altitudeAccuracy : Maybe.Maybe Length.Length, headingWith0AsTrueNorthAndIncreasingClockwise : Maybe.Maybe Angle.Angle, speed : Maybe.Maybe Speed.Speed }"},{"name":"HttpMetadata","comment":" Extra information about the response:\n\n - url of the server that actually responded (so you can detect redirects)\n - statusCode like 200 or 404\n - statusText describing what the statusCode means a little\n - headers like Content-Length and Expires\n\nNote: It is possible for a response to have the same header multiple times.\nIn that case, all the values end up in a single entry in the headers dictionary.\nThe values are separated by commas, following the rules outlined [here](https://stackoverflow.com/questions/4371328/are-duplicate-http-response-headers-acceptable).\n\n","args":[],"type":"RecordWithoutConstructorFunction.RecordWithoutConstructorFunction { url : String.String, statusCode : Basics.Int, statusText : String.String, headers : Dict.Dict String.String String.String }"},{"name":"HttpRequest","comment":" An HTTP request for use in an [`Interface`](#Interface).\n\nYou can set custom headers as needed.\nThe `timeout` can be set to a number of milliseconds you are willing to wait before giving up\n\n","args":["future"],"type":"RecordWithoutConstructorFunction.RecordWithoutConstructorFunction { url : String.String, method : String.String, headers : List.List { name : String.String, value : String.String }, body : Web.HttpBody, expect : Web.HttpExpect future, timeout : Maybe.Maybe Basics.Int }"},{"name":"HttpRequestId","comment":" Safe to ignore. Identifier for an [`HttpRequest`](#HttpRequest)\n","args":[],"type":"RecordWithoutConstructorFunction.RecordWithoutConstructorFunction { url : String.String, method : String.String, headers : List.List { name : String.String, value : String.String }, body : Web.HttpBody, expect : Web.HttpExpectId, timeout : Maybe.Maybe Basics.Int }"},{"name":"Interface","comment":" Incoming and outgoing effects.\nTo create one, use the helpers in [`Web.Time`](Web-Time), [`Web.Dom`](Web-Dom), [`Web.Http`](Web-Http) etc.\n\nTo combine multiple, use [`Web.interfaceBatch`](#interfaceBatch) and [`Web.interfaceNone`](#interfaceNone)\n\n","args":["future"],"type":"Rope.Rope (Web.InterfaceSingle future)"},{"name":"Program","comment":" A [`Platform.Program`](https://dark.elm.dmy.fr/packages/elm/core/latest/Platform#Program)\nthat elm can run,\nproduced by [`Web.program`](#program)\n","args":["state"],"type":"Platform.Program () (Web.ProgramState state) (Web.ProgramEvent state)"},{"name":"ProgramConfig","comment":" What's needed to create a state-interface program.\n\n - the state is everything the program knows (what The Elm Architecture calls model)\n\n - The [`Interface`](#Interface) is the face to the outside world and can be created using the helpers in [`Web.Dom`](Web-Dom), [`Web.Time`](Web-Time), [`Web.Http`](Web-Http) etc.\n\n - connections to and from js\n\n port toJs : Json.Encode.Value -> Cmd event_\n\n port fromJs : (Json.Encode.Value -> event) -> Sub event\n\n","args":["state"],"type":"RecordWithoutConstructorFunction.RecordWithoutConstructorFunction { initialState : state, interface : state -> Web.Interface state, ports : { toJs : Json.Encode.Value -> Platform.Cmd.Cmd Basics.Never, fromJs : (Json.Encode.Value -> Web.ProgramEvent state) -> Platform.Sub.Sub (Web.ProgramEvent state) } }"}],"values":[{"name":"findInterfaceAssociatedWithDiffComingBack","comment":" Quickly find out what [interface](#InterfaceSingleWithFuture) a given\n[diff](#InterfaceWithFutureDiff) that comes back belonged to.\n\nUse in combination with [`interfaceFutureJsonDecoder`](#interfaceFutureJsonDecoder) to feed it the event data json that comes back\n\n","type":"Web.InterfaceWithFutureDiff -> FastDict.Dict (List.List String.String) (Web.InterfaceSingle future) -> Maybe.Maybe (Web.InterfaceSingleWithFuture future)"},{"name":"interfaceBatch","comment":" Combine multiple [`Interface`](#Interface)s into one.\n","type":"List.List (Web.Interface future) -> Web.Interface future"},{"name":"interfaceDiffs","comment":" Determine which outgoing effects need to be executed based on the difference between old and updated interfaces\n\nTo for example determine the initial effects, use\n\n { old = Set.StructuredId.empty, updated = initialInterface }\n |> interfaceDiffs\n\n","type":"{ old : FastDict.Dict (List.List String.String) (Web.InterfaceSingle future), updated : FastDict.Dict (List.List String.String) (Web.InterfaceSingle future) } -> List.List Web.InterfaceDiff"},{"name":"interfaceFutureJsonDecoder","comment":" [json `Decoder`](https://dark.elm.dmy.fr/packages/elm/json/latest/Json-Decode#Decoder)\nfor the transformed event data coming back\n","type":"Web.InterfaceSingleWithFuture future -> Json.Decode.Decoder future"},{"name":"interfaceFutureMap","comment":" Take what the [`Interface`](#Interface) can come back with and return a different future value.\n\nIn practice, this is sometimes used like a kind of event-config pattern:\n\n Web.Time.posixRequest\n |> Web.interfaceFutureMap (\\timeNow -> TimeReceived timeNow)\n\n button \"show all entries\"\n |> Web.Dom.render\n |> Web.interfaceFutureMap (\\Pressed -> ShowAllEntriesButtonClicked)\n\nsometimes as a way to deal with all events (like `update` in The Elm Architecture)\n\n ...\n |> Web.interfaceFutureMap\n (\\event ->\n case event of\n MouseMovedTo newMousePoint ->\n { state | mousePoint = newMousePoint }\n\n CounterDecreaseClicked ->\n { state | counter = state.counter - 1 }\n\n CounterIncreaseClicked ->\n { state | counter = state.counter + 1 }\n )\n\nand sometimes to nest events (like `Cmd.map/Task.map/Sub.map/...` in The Elm Architecture):\n\n type Event\n = DirectoryTreeViewEvent TreeUiEvent\n | SortButtonClicked\n\n type TreeUiEvent\n = Expanded TreePath\n | Collapsed TreePath\n\n interface : State -> Interface State\n interface state =\n ...\n [ treeUi ..\n |> Web.interfaceFutureMap DirectoryTreeViewEvent\n , ...\n ]\n |> Web.Dom.render\n\n treeUi : ... -> Web.DomNode TreeUiEvent\n\nIn all these examples, you end up converting the narrow future representation of part of the interface\nto a broader representation for the parent interface\n\n","type":"(future -> mappedFuture) -> Web.Interface future -> Web.Interface mappedFuture"},{"name":"interfaceNone","comment":" Doing nothing as an [`Interface`](#Interface). These two examples are equivalent:\n\n Web.interfaceBatch [ a, Web.interfaceNone, b ]\n\nand\n\n Web.interfaceBatch\n (List.filterMap identity\n [ a |> Just, Nothing, b |> Just ]\n )\n\n","type":"Web.Interface future_"},{"name":"program","comment":" Create an elm [`Program`](https://dark.elm.dmy.fr/packages/elm/core/latest/Platform#Program)\nwith a given [`Web.ProgramConfig`](#ProgramConfig).\n","type":"Web.ProgramConfig state -> Web.Program state"},{"name":"programInit","comment":" The \"init\" part for an embedded program\n","type":"Web.ProgramConfig state -> ( Web.ProgramState state, Platform.Cmd.Cmd (Web.ProgramEvent state) )"},{"name":"programSubscriptions","comment":" The \"subscriptions\" part for an embedded program\n","type":"Web.ProgramConfig state -> Web.ProgramState state -> Platform.Sub.Sub (Web.ProgramEvent state)"},{"name":"programUpdate","comment":" The \"update\" part for an embedded program\n","type":"Web.ProgramConfig state -> Web.ProgramEvent state -> Web.ProgramState state -> ( Web.ProgramState state, Platform.Cmd.Cmd (Web.ProgramEvent state) )"}],"binops":[]},{"name":"Web.Audio","comment":" Play [`Audio`](Web#Audio) as part of an [`Interface`](Web#Interface).\n\n import Time\n import Web\n import Web.Audio\n\n type alias State =\n { musicSource : Maybe (Result Web.AudioSourceLoadError Audio.Source)\n , musicStartTime : Time.Posix\n , soundSetting : SoundSetting\n }\n\n type SoundSetting\n = SoundOn\n | SoundOff\n\n { initialState =\n { musicSource = Nothing\n , soundSetting = SoundOn\n , musicStartTime = Time.millisToPosix 0\n }\n , interface =\n \\state ->\n case state.musicSource of\n Just (Ok musicSource) ->\n case state.soundSetting of\n SoundOff ->\n Web.interfaceNone\n\n SoundOn ->\n Web.Audio.fromSource musicSource model.musicStartTime\n |> Web.Audio.play\n\n _ ->\n Web.Audio.sourceLoad \"https://archive.org/details/lp_the-caretakers-original-motion-picture-sco_elmer-bernstein/disc1/01.03.+Take+Care.mp3\"\n |> Web.interfaceFutureMap\n (\\result -> { state | musicSource = result |> Just })\n }\n\n@docs sourceLoad, fromSource, play\n@docs volumeScaleBy, speedScaleBy, stereoPan\n@docs addLinearConvolutionWith, addHighpassFromFrequency, addLowpassUntilFrequency\n\nTo detune, use [`speedScaleBy`](#speedScaleBy). It's documentation also shows which scale relates to which semitone pitch.\n\n","unions":[],"aliases":[],"values":[{"name":"addHighpassFromFrequency","comment":" Frequencies below a given cutoff [parameter](Web#AudioParameterTimeline) are attenuated;\nfrequencies above it pass through.\n\nHas a 12dB/octave rolloff and no peak at the cutoff.\n\n","type":"Web.AudioParameterTimeline -> Web.Audio -> Web.Audio"},{"name":"addLinearConvolutionWith","comment":" Usually used to apply reverb and or echo.\nGiven a loaded [`AudioSource`](Web#AudioSource) containing the impulse response,\nit performs a [Convolution](https://en.wikipedia.org/wiki/Convolution) with the [`Audio`](Web#Audio)\n\nIf you need some nice impulse wavs to try it out, there's a few at [`dhiogoboza/audio-convolution`](https://github.com/dhiogoboza/audio-convolution/tree/master/impulses).\nIf you know more nice ones, don't hesitate to open an issue or a PR.\n\n","type":"Web.AudioSource -> Web.Audio -> Web.Audio"},{"name":"addLowpassUntilFrequency","comment":" Frequencies below a given cutoff [parameter](Web#AudioParameterTimeline) pass through;\nfrequencies above it are attenuated.\n\nHas a 12dB/octave rolloff and no peak at the cutoff.\n\n","type":"Web.AudioParameterTimeline -> Web.Audio -> Web.Audio"},{"name":"fromSource","comment":" Create [`Audio`](Web#Audio) from an given loaded [source](Web#AudioSource)\nwhich will play at a given [time](https://dark.elm.dmy.fr/packages/elm/time/latest/)\n\n -- play a song at half speed and wait 2 seconds after the usual song start time before starting\n Web.Audio.fromSource\n myCoolSong\n (Duration.addTo usualSongStartTime (Duration.seconds 2))\n |> Web.Audio.speedScaleBy (Web.Audio.Parameter.at 0.5)\n\nNote that in some browsers audio will be muted until the user interacts with the webpage.\n\n","type":"Web.AudioSource -> Time.Posix -> Web.Audio"},{"name":"play","comment":" An [`Interface`](Web#Interface) for playing [`Audio`](Web#Audio) created with [`fromSource`](#fromSource).\n\nTo play multiple audios:\n\n [ audio0, audio1, audio2 ]\n |> List.map Web.Audio.play\n |> Web.interfaceBatch\n\n","type":"Web.Audio -> Web.Interface future_"},{"name":"sourceLoad","comment":" An [`Interface`](Web#Interface) for fetching audio data from a given url\nand returning an [`AudioSource`](Web#AudioSource) to use with [`fromSource`](#fromSource).\n","type":"String.String -> Web.Interface (Result.Result Web.AudioSourceLoadError Web.AudioSource)"},{"name":"speedScaleBy","comment":" Scale the playback rate by a given factor. This will also affect pitch.\n\nFor example, `Web.Audio.speedScaleBy 0.5` means playback will take twice as long and the pitch will be one octave lower, see [AudioBufferSourceNode.playbackRate](https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode/playbackRate)\n\nIn general, to pitch by semitones:\n\n Web.Audio.speedScaleBy (2 ^ (semitones / 12))\n\nNote: It would be possible to modify the signal to compensate for the pitch change,\nsee [Audio time stretching and pitch scaling](https://en.wikipedia.org/wiki/Audio_time_stretching_and_pitch_scaling).\nHelp appreciated!\n\n","type":"Web.AudioParameterTimeline -> Web.Audio -> Web.Audio"},{"name":"stereoPan","comment":" Change the stereo panning with a given a signed percentage [parameter](Web#AudioParameterTimeline).\n\nFor example `Web.Audio.pan -0.9` means that the sound is almost fully balanced towards the left speaker\n\n","type":"Web.AudioParameterTimeline -> Web.Audio -> Web.Audio"},{"name":"volumeScaleBy","comment":" Scale how loud it is.\n1 preserves the current volume, 0.5 halves it, and 0 mutes it.\nIf the the volume is less than 0, 0 will be used instead.\n","type":"Web.AudioParameterTimeline -> Web.Audio -> Web.Audio"}],"binops":[]},{"name":"Web.Audio.Parameter","comment":" Build an [`AudioParameterTimeline`](Web#AudioParameterTimeline)\n\n@docs at, through\n\n","unions":[],"aliases":[],"values":[{"name":"at","comment":" Set it to a constant value. Add [`through`](#through) to make it transition from this starting value over time.\n","type":"Basics.Float -> Web.AudioParameterTimeline"},{"name":"through","comment":" Specify a key value at a given absolute point in time.\nThe parameter will then transition linearly between those points.\n\nLet's define an audio function that fades in to 1 and then fades out until it's 0 again.\n\n import Duration\n import Time\n import Web.Audio.Parameter\n\n\n -- 1 ________\n -- / \\\n -- 0 ____________/ \\_______\n -- t -> fade in fade out\n fadeInOut fadeInStartTime fadeOutEndTime audio =\n Web.Audio.Parameter.at 0\n |> Web.Audio.Parameter.through fadeInStartTime 1\n |> Web.Audio.Parameter.through (Duration.addTo fadeInStartTime Duration.second) 1\n |> Web.Audio.Parameter.through (Duration.subtractFrom fadeOutEndTime Duration.second) 1\n |> Web.Audio.Parameter.through fadeOutEndTime 0\n\n - 🧩 `Duration` is from [ianmackenzie/elm-units](https://dark.elm.dmy.fr/packages/ianmackenzie/elm-units/latest/)\n - 🧩 `Time` is from [elm/time](https://dark.elm.dmy.fr/packages/elm/time/latest/)\n\nYou do not have to worry about order.\n\n","type":"Time.Posix -> Basics.Float -> Web.AudioParameterTimeline -> Web.AudioParameterTimeline"}],"binops":[]},{"name":"Web.Clipboard","comment":" Helpers for clipboard interactions as part of an [`Interface`](Web#Interface)\n\n@docs request, replaceBy\n\nNote: To listen for [copy, cut and paste events](https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent),\nuse [`Web.Dom.listenTo`](Web-Dom#listenTo)\n\n","unions":[],"aliases":[],"values":[{"name":"replaceBy","comment":" An [`Interface`](Web#Interface) for setting the textual contents of the system clipboard.\n\nNote: uses [`navigator.clipboard.writeText`](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText)\n\n","type":"String.String -> Web.Interface future_"},{"name":"request","comment":" An [`Interface`](Web#Interface) for reading the textual contents of the system clipboard.\n\nNote: uses [`navigator.clipboard.readText`](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/readText)\n\n","type":"Web.Interface String.String"}],"binops":[]},{"name":"Web.Console","comment":" Helpers for console interactions as part of an [`Interface`](Web#Interface)\n\n@docs log, warn, error\n\n","unions":[],"aliases":[],"values":[{"name":"error","comment":" An [`Interface`](Web#Interface) for printing a message that something failed with bad consequences, for example\n\n> ❌ decoding the selected file failed. Please report this bug at ...\n\nNote: uses [`console.error`](https://developer.mozilla.org/en-US/docs/Web/API/console/error_static)\n\n","type":"String.String -> Web.Interface future_"},{"name":"log","comment":" An [`Interface`](Web#Interface) for printing a message with general information\nlike if certain tasks have been successful\n\n> survey submitted and received successfully\n\nDepending on what minifying tools you use for your production build, these might get removed.\n\nNote: uses [`console.log`](https://developer.mozilla.org/en-US/docs/Web/API/console/log_static),\njust like [`Debug.log`](https://dark.elm.dmy.fr/packages/elm/core/latest/Debug#log)\n\n","type":"String.String -> Web.Interface future_"},{"name":"warn","comment":" An [`Interface`](Web#Interface) for printing a message that something didn't succeed but you could recover from, for example\n\n> ⚠️ Unknown device - there may be compatibility issues.\n\n> ⚠️ Recoverable upload failure, will retry. Error was: no status.\n\nNote: uses [`console.warn`](https://developer.mozilla.org/en-US/docs/Web/API/console/warn_static)\n\n","type":"String.String -> Web.Interface future_"}],"binops":[]},{"name":"Web.Dom","comment":" Helpers for [DOM node types](Web#DomNode) as part of an [`Interface`](Web#Interface).\n\nThese are primitives used for svg and html.\nCompare with [`elm/virtual-dom`](https://dark.elm.dmy.fr/packages/elm/virtual-dom/latest/)\n\n@docs text\n@docs element, elementNamespaced\n@docs Modifier, ModifierSingle, attribute, attributeNamespaced, style\n@docs listenTo, listenToPreventingDefaultAction\n@docs scrollToShow, scrollPositionRequest, scrollToPosition\n@docs modifierFutureMap, modifierBatch, modifierNone\n@docs futureMap, render\n\n","unions":[{"name":"ModifierSingle","comment":" An individual [`Modifier`](#Modifier).\nCreate using [`attribute`](#attribute), [`style`](#style), [`listenTo`](#listenTo).\n","args":["future"],"cases":[["Attribute",["{ namespace : Maybe.Maybe String.String, key : String.String, value : String.String }"]],["Style",["{ key : String.String, value : String.String }"]],["ScrollToPosition",["{ fromLeft : Basics.Float, fromTop : Basics.Float }"]],["ScrollToShow",["{ x : Web.DomElementVisibilityAlignment, y : Web.DomElementVisibilityAlignment }"]],["ScrollPositionRequest",["{ fromLeft : Basics.Float, fromTop : Basics.Float } -> future"]],["Listen",["{ eventName : String.String, on : Json.Decode.Value -> future, defaultActionHandling : Web.DefaultActionHandling }"]]]}],"aliases":[{"name":"Modifier","comment":" Set the behavior of a [`Web.Dom.element`](Web-Dom#element).\nTo create one, use [`attribute`](#attribute), [`style`](#style), [`listenTo`](#listenTo).\nTo combine multiple, use [`Web.Dom.modifierBatch`](#modifierBatch) and [`Web.Dom.modifierNone`](#modifierNone)\n\nFor example to get `elm`\n\n Web.Dom.element \"a\"\n [ Web.Dom.attribute \"href\" \"https://elm-lang.org\" ]\n [ Web.Dom.text \"elm\" ]\n\nBtw: If you can think of a nicer name for this like \"customization\", \"characteristic\" or \"aspect\",\nplease [open an issue](https://github.com/lue-bird/elm-state-interface/issues/new)!\n\n","args":["future"],"type":"Rope.Rope (Web.Dom.ModifierSingle future)"}],"values":[{"name":"attribute","comment":" A key-value attribute [`Modifier`](#Modifier)\n","type":"String.String -> String.String -> Web.Dom.Modifier future_"},{"name":"attributeNamespaced","comment":" A namespaced key-value attribute [`Modifier`](#Modifier).\nFor example, you could define an SVG xlink href attribute as\n\n attributeXlinkHref : String -> Modifier msg\n attributeXlinkHref value =\n Web.Dom.attributeNamespaced \"http://www.w3.org/1999/xlink\" \"xlink:href\" value\n\n","type":"String.String -> String.String -> String.String -> Web.Dom.Modifier future_"},{"name":"element","comment":" Create a DOM element with a given tag, [`Modifier`](#Modifier)s and sub-[node](Web#DomNode)s.\nFor example to get `

flying

`\n\n Web.Dom.element \"p\"\n []\n [ Web.Dom.text \"flying\" ]\n\nTo create SVG elements, use [`Web.Svg.element`](Web-Svg#element)\n\n","type":"String.String -> List.List (Web.Dom.Modifier future) -> List.List (Web.DomNode future) -> Web.DomNode future"},{"name":"elementNamespaced","comment":" Create a DOM element with a given namespace, tag, [`Modifier`](#Modifier)s and sub-[node](Web#DomNode)s.\nFor example, [`Web.Svg`](Web-Svg) defines its elements using\n\n element : String -> List (Modifier future) -> List (DomNode future) -> DomNode future\n element tag modifiers subs =\n Web.Dom.elementNamespaced \"http://www.w3.org/2000/svg\" tag modifiers subs\n\n","type":"String.String -> String.String -> List.List (Web.Dom.Modifier future) -> List.List (Web.DomNode future) -> Web.DomNode future"},{"name":"futureMap","comment":" Wire events from this [`DomNode`](Web#DomNode) to a specific event.\n\n buttonUi \"start\"\n |> Web.Dom.futureMap (\\Clicked -> StartButtonClicked)\n\nwith e.g.\n\n buttonUi : List (Web.DomNode ()) -> Web.DomNode ButtonEvent\n buttonUi subs =\n Web.Dom.element \"button\"\n [ Web.Dom.listenTo \"click\"\n |> Web.Dom.modifierFutureMap (\\_ -> Clicked)\n ]\n [ Web.Dom.text label ]\n\n type ButtonEvent\n = Clicked\n\n","type":"(future -> mappedFuture) -> Web.DomNode future -> Web.DomNode mappedFuture"},{"name":"listenTo","comment":" Listen for a specific DOM event on the [`DomElement`](Web#DomElement).\nUse [`modifierFutureMap`](#modifierFutureMap) to wire this to a specific event.\n\nIf you want to override the browser's default behavior for that event,\nuse [`listenToPreventingDefaultAction`](#listenToPreventingDefaultAction)\n\n","type":"String.String -> Web.Dom.Modifier Json.Decode.Value"},{"name":"listenToPreventingDefaultAction","comment":" Like [`listenTo`](#listenTo) but [preventing the browser's default action](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault).\n\nThat's for example how elm's [`Browser.Events.onSubmit`](https://dark.elm.dmy.fr/packages/elm/html/latest/Html-Events#onSubmit)\nprevents the form from changing the page’s location:\n\n submitListen : Web.Dom.Modifier ()\n submitListen =\n Web.Dom.listenToPreventingDefaultAction \"submit\"\n |> Web.Dom.modifierFutureMap (\\_ -> ())\n\n","type":"String.String -> Web.Dom.Modifier Json.Decode.Value"},{"name":"modifierBatch","comment":" Combine multiple [`Modifier`](#Modifier)s into one.\n","type":"List.List (Web.Dom.Modifier future) -> Web.Dom.Modifier future"},{"name":"modifierFutureMap","comment":" Wire events from this [`Modifier`](#Modifier) to a specific event.\n\n Web.Dom.listen \"click\" |> Web.Dom.modifierFutureMap (\\_ -> ButtonClicked)\n\n","type":"(future -> mappedFuture) -> Web.Dom.Modifier future -> Web.Dom.Modifier mappedFuture"},{"name":"modifierNone","comment":" Doing nothing as a [`Modifier`](#Modifier). These two examples are equivalent:\n\n Web.Dom.modifierBatch\n [ a, Web.Dom.modifierNone, b ]\n\nand\n\n Web.Dom.modifierBatch\n (List.filterMap identity\n [ a |> Just, Nothing, b |> Just ]\n )\n\n","type":"Web.Dom.Modifier future_"},{"name":"render","comment":" An [`Interface`](Web#Interface) for displaying a given [`DomNode`](Web#DomNode).\n","type":"Web.DomNode future -> Web.Interface future"},{"name":"scrollPositionRequest","comment":" Getting the current scroll position from the left and top.\n\nUse in combination with [`scrollToPosition`](#scrollToPosition)\nto implement saving and restoring scroll position even when users had navigated off a URL.\n\n","type":"Web.Dom.Modifier { fromLeft : Basics.Float, fromTop : Basics.Float }"},{"name":"scrollToPosition","comment":" Ensure a given initial scroll position in both directions.\nTo move to the edge in a direction, use [`scrollToShow`](#scrollToShow) instead.\n\nUnlike [`style`](#style)s,\nthis is just an initial configuration\nwhich can be changed by user actions.\nSo adding e.g. `scrollToPosition ...`\nwill scroll once the next render happens\nbut will not prevent users from scrolling away.\n\n","type":"{ fromLeft : Basics.Float, fromTop : Basics.Float } -> Web.Dom.Modifier future_"},{"name":"scrollToShow","comment":" Ensure a given initial [`DomElementVisibilityAlignment`](Web#DomElementVisibilityAlignment)\nin both directions.\n\nUnlike [`style`](#style)s,\nthis is just an initial configuration\nwhich can be changed by user actions.\nSo adding e.g. `scrollToShow { y = Web.DomElementStart, x = Web.DomElementStart }`\nwill scroll to the top left once the next render happens\nbut will not prevent users from scrolling away.\n\nNote: Uses [`Element.scrollIntoView`](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView)\n\n","type":"{ x : Web.DomElementVisibilityAlignment, y : Web.DomElementVisibilityAlignment } -> Web.Dom.Modifier future_"},{"name":"style","comment":" A key-value style [`Modifier`](#Modifier)\n","type":"String.String -> String.String -> Web.Dom.Modifier future_"},{"name":"text","comment":" Plain text [`DomNode`](Web#DomNode)\n","type":"String.String -> Web.DomNode future_"}],"binops":[]},{"name":"Web.FileDownload","comment":" Helpers for downloading a dynamically generated file as part of an [`Interface`](Web#Interface).\n\nSecurity note: Browsers require downloads to be initiated by a user event.\nSo rather than allowing malicious sites to put files on your computer however they please,\nthe user has to at least click a button first.\nAs a result, the following interfaces only work when they are triggered by some user event.\n\nNote: There's no equivalent module for file select\nsince you can easily replicate the behavior using an input element with type file or file drop area modifiers,\nsee for example [mpizenberg/elm-file](https://dark.elm.dmy.fr/packages/mpizenberg/elm-file/latest/FileValue#load-files-with-an-input).\n\n@docs bytes\n\n","unions":[],"aliases":[],"values":[{"name":"bytes","comment":" An [`Interface`](Web#Interface) for downloading a given file\nwith [`Bytes`](https://dark.elm.dmy.fr/packages/elm/bytes/latest/) as its content,\na given type and and a given default name.\n\nReplacement for [`File.Download.bytes`](https://dark.elm.dmy.fr/packages/elm/file/latest/File-Download#bytes)\n\n","type":"{ name : String.String, mimeType : String.String, content : Bytes.Bytes } -> Web.Interface future_"}],"binops":[]},{"name":"Web.Gamepads","comment":" Observe connected [gamepads and other game controllers](Web#Gamepad)\n(not including motion sensing, gesture recognition etc.).\n\n import Web.Time\n import Web\n\n interface =\n \\state ->\n [ Web.Time.periodicallyListen (Duration.seconds (1 / 50))\n |> Web.interfaceFutureMap\n ..simulate one tick using gamepad inputs..\n , [ Web.Gamepads.request, Web.Gamepads.changeListen ]\n |> Web.interfaceBatch\n |> Web.interfaceFutureMap (\\gamepads -> { state | gamepads = gamepads })\n ]\n |> Web.interfaceBatch\n\nIf your gamepad isn't showing up in the list,\npress some buttons. On some devices, only certain buttons will wake up the gamepad API (the shapes on PS3 controllers, for instance)\n\n@docs request, changeListen\n\n","unions":[],"aliases":[],"values":[{"name":"changeListen","comment":" An [`Interface`](Web#Interface) for detecting changes to which [gamepads](Web#Gamepad)\nare connected and in which ways buttons and axes are activated.\n\nThe given `Dict` keys uniquely identify each device for the whole session,\nso you can for example check for removed and added gamepads using `Dict.diff`\nor track one host device in the state.\n\nImplementation note:\nThe [web gamepad API](https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API) does not offer a listener to detect changes.\nSo instead, we poll every 14ms (a bit more often than 60 times/second)\nwhich is just a bit faster than Chrome's actual fetch rate (fetch rate is not part of the specification).\n\nWe want to avoid missed inputs before your next simulation tick,\nso we just had to guess a good interval number.\n\n\nIf you have issues with unresponsiveness, [open an issue](https://github.com/lue-bird/elm-state-interface/issues/new)\n\n","type":"Web.Interface (Dict.Dict Basics.Int Web.Gamepad)"},{"name":"request","comment":" An [`Interface`](Web#Interface) for getting which [gamepads](Web#Gamepad)\nare connected and in which ways buttons and axes are activated.\n\nThe given `Dict` keys uniquely identify each device for the whole session.\n\n","type":"Web.Interface (Dict.Dict Basics.Int Web.Gamepad)"}],"binops":[]},{"name":"Web.GeoLocation","comment":" Observe the [`GeoLocation`](Web#GeoLocation) as part of an [`Interface`](Web#Interface)\nusing the [web geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API).\n\n@docs request, changeListen\n\n","unions":[],"aliases":[],"values":[{"name":"changeListen","comment":" An [`Interface`](Web#Interface) for detecting changes in the current [position of the device](Web#GeoLocation)\n","type":"Web.Interface Web.GeoLocation"},{"name":"request","comment":" An [`Interface`](Web#Interface) for getting the current [position of the device](Web#GeoLocation)\n","type":"Web.Interface Web.GeoLocation"}],"binops":[]},{"name":"Web.Http","comment":" Helpers for [HTTP types](Web#HttpRequest) as part of an [`Interface`](Web#Interface)\n\n@docs expectString, expectJson, expectBytes, expectWhatever\n\n@docs bodyJson, bodyBytes\n\n@docs get, post\n\n@docs request\n\n","unions":[],"aliases":[],"values":[{"name":"bodyBytes","comment":" Put given [`Bytes`](https://dark.elm.dmy.fr/packages/elm/bytes/latest/) in the body of your request.\nThe string argument should be a [MIME type](https://en.wikipedia.org/wiki/Media_type) to be used in the `Content-Type` header\n\n import Bytes exposing (Bytes)\n import Time\n import Web\n import Zip\n import Zip.Entry\n\n exampleZipBody : Web.HttpBody\n exampleZipBody =\n Web.Http.bodyBytes \"application/zip\"\n (Zip.fromEntries\n [ Encode.string \"Hello, World!\"\n |> Encode.encode\n |> store\n { path = \"hello.txt\"\n , lastModified = ( Time.utc, Time.millisToPosix 0 )\n , comment = Nothing\n }\n ]\n |> Zip.toBytes\n )\n\n`Zip` and `Zip.Entry` are from [`agu-z/elm-zip`](https://dark.elm.dmy.fr/packages/agu-z/elm-zip/latest/)\n\n","type":"String.String -> Bytes.Bytes -> Web.HttpBody"},{"name":"bodyJson","comment":" Put a given JSON value in the body of your request. This will automatically add the `Content-Type: application/json` header.\n","type":"Json.Encode.Value -> Web.HttpBody"},{"name":"expectBytes","comment":" Expect the response body to be [`Bytes`](https://dark.elm.dmy.fr/packages/elm/bytes/latest/).\nThe result will either be\n\n - `Err` with an [`HttpError`](Web#HttpError) if it didn't succeed\n - `Ok` with the `Bytes`\n\n","type":"Web.HttpExpect (Result.Result Web.HttpError Bytes.Bytes)"},{"name":"expectJson","comment":" Expect the response body to be `JSON`, decode it using the given decoder.\nThe result will either be\n\n - `Err` with an [`HttpError`](Web#HttpError) if it didn't succeed\n - `Ok` if there was a result with either\n - `Ok` with the decoded value\n - `Err` with a [`Json.Decode.Error`](https://dark.elm.dmy.fr/packages/elm/json/latest/Json-Decode#Error) the actual text response\n\n","type":"Json.Decode.Decoder future -> Web.HttpExpect (Result.Result Web.HttpError (Result.Result { actualBody : String.String, jsonError : Json.Decode.Error } future))"},{"name":"expectString","comment":" Expect the response body to be a `String`.\n","type":"Web.HttpExpect (Result.Result Web.HttpError String.String)"},{"name":"expectWhatever","comment":" Discard the response body.\n","type":"Web.HttpExpect (Result.Result Web.HttpError ())"},{"name":"get","comment":" Create a `GET` [`HttpRequest`](Web#HttpRequest)\n","type":"{ url : String.String, headers : List.List ( String.String, String.String ), expect : Web.HttpExpect future, timeout : Maybe.Maybe Basics.Int } -> Web.HttpRequest future"},{"name":"post","comment":" Create a `POST` [`HttpRequest`](Web#HttpRequest)\n","type":"{ url : String.String, headers : List.List ( String.String, String.String ), body : Web.HttpBody, expect : Web.HttpExpect future, timeout : Maybe.Maybe Basics.Int } -> Web.HttpRequest future"},{"name":"request","comment":" An [`Interface`](Web#Interface) for handling an [`HttpRequest`](Web#HttpRequest)\nusing the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)\n","type":"Web.HttpRequest future -> Web.Interface future"}],"binops":[]},{"name":"Web.LocalStorage","comment":" Saved data for the url origin (protocol, host name, port) across browser sessions.\n\nThis data doesn't expire and won't be cleared when the page is closed.\nThe only exception is \"incognito mode\", where all data is cleared once the last \"private\" tab is closed.\n\nsee [mdn on `Window.localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)\n\n@docs request, set, remove\n@docs setOnADifferentTabListen, removeOnADifferentTabListen\n\n","unions":[],"aliases":[],"values":[{"name":"remove","comment":" An [`Interface`](Web#Interface) for deleting the entry with the given key if it exists.\n\nNote: This will trigger an event for all other tabs of the same url origin\nthat can be listened to using [`removeOnADifferentTabListen`](#removeOnADifferentTabListen)\n\n","type":"String.String -> Web.Interface future_"},{"name":"removeOnADifferentTabListen","comment":" An [`Interface`](Web#Interface) for keeping an eye on\nwhen the local storage on a different tab with the same url origin is removed.\n","type":"String.String -> Web.Interface AppUrl.AppUrl"},{"name":"request","comment":" An [`Interface`](Web#Interface) for reading the value of the entry with the given key.\nComes back with `Nothing` if that key doesn't exist.\n\n import Json.Decode\n import Web\n\n projectFromLocalStorageRequest : Web.Interface (Result String Project)\n projectFromLocalStorageRequest =\n Web.LocalStorage.request \"project\"\n |> Web.interfaceFutureMap\n (\\savedProject ->\n case savedProject of\n Nothing ->\n \"nothing had been saved\" |> Err\n\n Just savedProjectJsonString ->\n savedProjectJsonString\n |> Json.Decode.decodeString projectJsonDecoder\n |> Result.mapError Json.Decode.errorToString\n )\n\n","type":"String.String -> Web.Interface (Maybe.Maybe String.String)"},{"name":"set","comment":" An [`Interface`](Web#Interface) for replacing the value of the entry with the given key\nor adding key and value as a new entry if the key doesn't exist.\n\n import Json.Decode\n import Web\n\n projectSaveToLocalStorage : Project -> Web.Interface future_\n projectSaveToLocalStorage =\n \\project ->\n Web.LocalStorage.set \"project\"\n (project |> projectJsonEncode |> Json.Encode.encode 0)\n\nNote: This will trigger an event for all other tabs of the same url origin\nthat can be listened to using [`setOnADifferentTabListen`](#setOnADifferentTabListen)\n\n","type":"String.String -> String.String -> Web.Interface future_"},{"name":"setOnADifferentTabListen","comment":" An [`Interface`](Web#Interface) for keeping an eye on\nwhen the local storage on a different tab with the same url origin is set.\n\nWhen the `oldValue` is `Nothing`, no entry with that key existed.\n\n","type":"String.String -> Web.Interface { appUrl : AppUrl.AppUrl, oldValue : Maybe.Maybe String.String, newValue : String.String }"}],"binops":[]},{"name":"Web.Navigation","comment":" Helpers for `history` interaction as part of an [`Interface`](Web#Interface)\n\n@docs urlRequest\n@docs pushUrl, replaceUrl\n@docs moveForward, moveBack, movementListen\n@docs load, reload\n\n","unions":[],"aliases":[],"values":[{"name":"load","comment":" An [`Interface`](Web#Interface) for leaving the current page and loading the given [URL](https://dark.elm.dmy.fr/packages/elm/url/latest/).\nThis always results in a page load, even if the provided URL is the same as the current one.\n\n gotoElmWebsite : Web.Interface future_\n gotoElmWebsite =\n Web.Navigation.load \"https://elm-lang.org/\"\n\nReplacement for [`Browser.Navigation.load`](https://dark.elm.dmy.fr/packages/elm/browser/latest/Browser-Navigation#load)\n\n","type":"String.String -> Web.Interface future_"},{"name":"moveBack","comment":" An [`Interface`](Web#Interface) for going back a given number of pages.\n\nNote: You only manage the browser history that you created.\n\nReplacement for [`Browser.Navigation.back`](https://dark.elm.dmy.fr/packages/elm/browser/latest/Browser-Navigation#back)\n\n","type":"Basics.Int -> Web.Interface future_"},{"name":"moveForward","comment":" An [`Interface`](Web#Interface) for going forward a given number of pages.\nIf there are no more pages in the future, this will do nothing.\n\nNote: You only manage the browser history that you created.\n\nReplacement for [`Browser.Navigation.forward`](https://dark.elm.dmy.fr/packages/elm/browser/latest/Browser-Navigation#forward)\n\n","type":"Basics.Int -> Web.Interface future_"},{"name":"movementListen","comment":" If you used [`pushUrl`](#pushUrl) to update the URL with new history entries,\nwhen the user clicks ← or → buttons (or you call [`moveForward`](#moveForward) or [`moveBack`](#moveBack) yourself),\nthe URL will change but your UI will not.\n\n[`movementListen`](#movementListen) is an [`Interface`](Web#Interface) for detecting those URL changes and making ui changes as needed.\n\nWhen the app itself initiates a url change with [`pushUrl`](#pushUrl) or [`replaceUrl`](#replaceUrl), no such event is triggered.\n\nNote: This event is called [\"popstate\"](https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event) in js\n\n","type":"Web.Interface AppUrl.AppUrl"},{"name":"pushUrl","comment":" An [`Interface`](Web#Interface) for changing the [app-specific URL](https://dark.elm.dmy.fr/packages/lydell/elm-app-url/latest/)\nand adding a new entry to the browser history\nwithout triggering a page load.\n\nReplacement for [`Browser.Navigation.pushUrl`](https://dark.elm.dmy.fr/packages/elm/browser/latest/Browser-Navigation#pushUrl)\n\n","type":"AppUrl.AppUrl -> Web.Interface future_"},{"name":"reload","comment":" An [`Interface`](Web#Interface) for reloading the current page.\nThis always results in a page load!\n\nNote: This may grab resources from the browser cache.\n\nReplacement for [`Browser.Navigation.reload`](https://dark.elm.dmy.fr/packages/elm/browser/latest/Browser-Navigation#reload)\n\n","type":"Web.Interface future_"},{"name":"replaceUrl","comment":" An [`Interface`](Web#Interface) for changing the [app-specific URL](https://dark.elm.dmy.fr/packages/lydell/elm-app-url/latest/),\nwithout triggering a page load or adding a new entry to the browser history.\n\nThis can be useful if you have search box and you want the ?search=hats in the URL to match without adding a history entry for every single key stroke.\nImagine how annoying it would be to click back thirty times and still be on the same page!\n\nReplacement for [`Browser.Navigation.replaceUrl`](https://dark.elm.dmy.fr/packages/elm/browser/latest/Browser-Navigation#replaceUrl)\n\n","type":"AppUrl.AppUrl -> Web.Interface future_"},{"name":"urlRequest","comment":" An [`Interface`](Web#Interface) for getting the current page's [app-specific URL](https://dark.elm.dmy.fr/packages/lydell/elm-app-url/latest/).\nIs usually used while starting up the app.\n\nNote: Uses [`window.location.href`](https://developer.mozilla.org/en-US/docs/Web/API/Window/location)\n\n","type":"Web.Interface AppUrl.AppUrl"}],"binops":[]},{"name":"Web.Notification","comment":" Give important notices to the user as push notifications.\nConsider this a convenience feature, not something users have to rely upon.\nAlways offer users alternative methods to view messages or initiate actions\nand allow users to opt out of getting more in the future.\n\n@docs askForPermission, show\n\nYou can combine it with [`Web.Window.visibilityChangeListen`](Web-Window#visibilityChangeListen)\nto only notify users when they're on a different page\n\n import Web\n\n type State\n = State\n { windowVisibility : Web.WindowVisibility\n , whoseMove : Player\n , mode : Mode\n , notificationPermissionToggle : Permission\n }\n\n type Permission\n = Rejected\n | Accepted\n\n type Mode\n = LongGameBoardMode\n | SettingsPage\n\n type Player\n = You\n | Opponent\n\n interface : State -> Web.Interface State\n interface =\n \\(State state) ->\n [ case state.notificationPermissionToggle of\n Accepted ->\n Web.Notification.askForPermission\n\n Rejected ->\n Web.interfaceNone\n , case ( state.windowVisibility, state.whoseTurn ) of\n ( Web.WindowHidden, You ) ->\n Web.Notification.show\n { message = \"opponent moved\", ... }\n |> Web.interfaceFutureMap\n (\\Web.NotificationClicked ->\n -- return to the game if previously in settings\n State { state | mode = LongGameBoardMode }\n )\n\n ( Web.WindowHidden, Opponent ) ->\n Web.interfaceNone\n\n ( Web.WindowShown, _ ) ->\n Web.interfaceNone\n , case state.mode of\n LongGameBoardMode ->\n ..listen for opponent move from server..\n |> Web.interfaceFutureMap\n (\\... -> State { state | whoseMove = You })\n\n SettingsPage ->\n ..toggle for accepting/rejecting notifications..\n |> Web.interfaceFutureMap\n (\\... -> State { state | notificationPermissionToggle = ..opposite.. })\n ]\n |> Web.interfaceBatch\n\n","unions":[],"aliases":[],"values":[{"name":"askForPermission","comment":" Ask the user to consent to receiving notifications, if they haven't already.\n\nFor security reasons, browsers require some kind of user interaction like a button click first.\nSo you could for example add a toggle to send notifications and ask only for permission\nwhen the toggle is set.\n\n","type":"Web.Interface future_"},{"name":"show","comment":" An [`Interface`](Web#Interface) for pushing a notification to the user.\nUsers can in the future [respond to it by clicking it](Web#NotificationClicked).\n\nTo not notify users multiple times for multiple messages of the same kind,\nchoose an `id` with a description for this kind\nso that the notification with the same kind gets silently replaced if it exists.\n\n case messagesFromOpponent of\n [] ->\n Web.interfaceNone\n\n [ onlyMessage ] ->\n Web.Notification.show\n { id = \"opponent messages\"\n , message = \"Your opponent left a message\"\n , details = \"\\\"\" ++ onlyMessage ++ \"\\\"\"\n }\n\n _ :: _ :: message2Up ->\n Web.Notification.show\n { id = \"opponent messages\"\n , message =\n [ \"Your opponent left \"\n , 2 + (message2Up |> List.length) |> String.fromInt\n , \" messages\"\n ]\n |> String.join\n , details = \"\"\n }\n\nAnother example of a reminder shown in advance\n\n let\n untilMeeting : Duration\n untilMeeting =\n Duration.from meetingTime currentTime\n in\n if untilMeeting |> Quantity.isLessThan (Duration.minutes 10) then\n Web.Notification.show\n { id = \"time until meeting\"\n , message =\n [ \"the meeting starts in \"\n , untilMeeting |> Duration.inMinutes |> Basics.ceiling |> String.fromInt)\n , \" minutes\"\n ]\n |> String.concat\n , details = \"\"\n }\n\n else\n Web.interfaceNone\n\nNote: If you haven't previously used [`askForPermission`](#askForPermission)\nit will request this permission now.\n\n","type":"{ message : String.String, details : String.String, id : String.String } -> Web.Interface Web.NotificationClicked"}],"binops":[]},{"name":"Web.Random","comment":" Helpers for randomness as part of an [`Interface`](Web#Interface).\nNot familiar with random \"generators\"? [`elm/random`](https://package.elm-lang.org/packages/elm/random/latest)\nexplains it nicely!\n\nHere's an example showing a number between 1 and 6 and a button to reroll\n\n import Random.Pcg.Extended\n import Web.Dom\n\n type State\n = WaitingForInitialRandomness\n | DiceUiState { diceEyes : Int, seed : Random.Pcg.Extended.Seed }\n\n type DiceUiEvent\n = RerollClicked\n\n diceEyesRandomGenerator : Random.Pcg.Extended.Generator Int\n diceEyesRandomGenerator =\n Random.Pcg.Extended.int 1 6\n\n { initialState = WaitingForInitialRandomness\n , interface =\n \\state ->\n case state of\n WaitingForInitialRandomness ->\n Web.Random.unsignedInt32s 4\n |> Web.futureMap\n (\\unsignedInt32s ->\n case unsignedIn32s of\n firstUint32 :: afterFirstUint32 ->\n let\n initialSeed : Random.Pcg.Extended.Seed\n initialSeed =\n Random.Pcg.Extended.initialSeed firstUint32 afterFirstUint32\n\n ( diceEyes, newSeed ) =\n Random.Pcg.Extended.step diceEyesRandomGenerator initialSeed\n in\n DiceUiState { diceEyes = diceEyes, seed = newSeed }\n\n [] ->\n WaitingForInitialRandomness\n )\n\n DiceUiState randomStuff ->\n Web.Dom.element \"div\"\n []\n [ randomStuff.diceEyes |> String.fromInt |> Web.Dom.text\n , Web.Dom.element \"button\"\n [ Web.Dom.listenTo \"click\"\n |> Web.Dom.modifierFutureMap (\\_ -> RerollClicked)\n ]\n [ \"roll the dice\" ]\n ]\n |> Web.Dom.render\n |> Web.interfaceFutureMap\n (\\RerollClicked ->\n let\n initialSeed : Random.Pcg.Extended.Seed\n initialSeed =\n Random.Pcg.Extended.initialSeed firstUnsignedInt32 afterFirstUnsignedInt32\n\n ( diceEyes, newSeed ) =\n Random.Pcg.Extended.step diceEyesRandomGenerator initialSeed\n in\n DiceUiState { diceEyes = diceEyes, seed = newSeed }\n )\n }\n\n@docs unsignedInt32s\n\n","unions":[],"aliases":[],"values":[{"name":"unsignedInt32s","comment":" An [`Interface`](Web#Interface) for generating a given count of cryptographically sound unsigned 32-bit `Int`s.\nYou can use these in all kinds of packages that allow creating an initial seed\nfrom ints like [NoRedInk/elm-random-pcg-extended](https://dark.elm.dmy.fr/packages/NoRedInk/elm-random-pcg-extended/latest/Random-Pcg-Extended#initialSeed)\n\nNote: uses [`window.crypto.getRandomValues`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues)\n\n","type":"Basics.Int -> Web.Interface (List.List Basics.Int)"}],"binops":[]},{"name":"Web.Socket","comment":" Helpers for [Socket types](Web#socket) as part of an [`Interface`](Web#Interface)\n\n\n## connection\n\n@docs connectTo, disconnect\n\n\n## communicate\n\n@docs message, messageListen\n\n","unions":[],"aliases":[],"values":[{"name":"connectTo","comment":" An [`Interface`](Web#Interface) for opening a connection on a given address,\nnotifying you when it's [connected or disconnected](Web#SocketConnectionEvent)\n\nOnce this detects it's available, make sure to set your state's [`SocketId`](Web#SocketId) so you can actually [send](#message)\nand [receive](#messageListen) messages.\nAnd once it's disconnected, set your state's [`SocketId`](Web#SocketId) back to nothing:\n\n case state.socketId of\n Nothing ->\n Web.Socket.connectTo \"ws://127.0.0.1:9000\"\n |> Web.interfaceMap\n (\\connectionChanged ->\n case connectionChanged of\n Web.SocketConnected socketId ->\n { state | socketId = socketId |> Just }\n\n Web.SocketDisconnected ->\n { state | socketId = Nothing }\n )\n\n Just socketId ->\n Web.Socket.message socketId \"Meow\"\n\n","type":"String.String -> Web.Interface Web.SocketConnectionEvent"},{"name":"disconnect","comment":" An [`Interface`](Web#Interface) for closing a given connection\n","type":"Web.SocketId -> Web.Interface future_"},{"name":"message","comment":" An [`Interface`](Web#Interface) for sending data to the server.\n\nIt's common to pair this with [`Json.Encode.encode 0`](https://dark.elm.dmy.fr/packages/elm/json/latest/Json-Encode#encode)\nto send json.\n\n","type":"Web.SocketId -> String.String -> Web.Interface future_"},{"name":"messageListen","comment":" An [`Interface`](Web#Interface) for detecting when data has been sent from the server\n","type":"Web.SocketId -> Web.Interface String.String"}],"binops":[]},{"name":"Web.Svg","comment":" Helpers for svg [DOM node types](Web#DomNode)\n\n@docs element\n\nfor text, attributes etc use the helpers in [`Web.Dom`](Web-Dom)\n\n","unions":[],"aliases":[],"values":[{"name":"element","comment":" Create an SVG element [`DomNode`](Web#DomNode).\nwith a given tag, [`Modifier`](Web-Dom#Modifier)s and sub-nodes.\n","type":"String.String -> List.List (Web.Dom.Modifier future) -> List.List (Web.DomNode future) -> Web.DomNode future"}],"binops":[]},{"name":"Web.Time","comment":" Helpers for [`elm/time`](https://dark.elm.dmy.fr/packages/elm/time/) primitives as part of an [`Interface`](Web#Interface).\n\n@docs posixRequest, zoneRequest, zoneNameRequest\n@docs periodicallyListen\n\n","unions":[],"aliases":[],"values":[{"name":"periodicallyListen","comment":" An [`Interface`](Web#Interface) for getting the current time\nevery time a given [`Duration`](https://dark.elm.dmy.fr/packages/ianmackenzie/elm-units/latest/Duration) has passed.\n\nNote: Do not use it for animations.\n[`Web.Window.animationFrameListen`](Web-Window#animationFrameListen)\nsyncs up with repaints and will end up being much smoother for any moving visuals.\n\n","type":"Duration.Duration -> Web.Interface Time.Posix"},{"name":"posixRequest","comment":" An [`Interface`](Web#Interface) for getting the [POSIX time](https://dark.elm.dmy.fr/packages/elm/time/latest/Time#Posix)\nat the moment it's added.\n\nReplacement for [`elm/time`'s `Time.now`](https://package.elm-lang.org/packages/elm/time/latest/Time#now).\n\n","type":"Web.Interface Time.Posix"},{"name":"zoneNameRequest","comment":" Intended for package authors.\nUse `Intl.DateTimeFormat().resolvedOptions().timeZone` to try to get names like Europe/Moscow or America/Havana.\nFrom there you can look it up in any [IANA data](https://www.iana.org/time-zones) you loaded yourself.\n\nReplacement for [`elm/time`'s `Time.getZoneName`](https://package.elm-lang.org/packages/elm/time/latest/Time#getZoneName).\n\n","type":"Web.Interface Time.ZoneName"},{"name":"zoneRequest","comment":" An [`Interface`](Web#Interface) for getting a [`Time.Zone`](https://dark.elm.dmy.fr/packages/elm/time/latest/Time#Zone)\nbased on the current UTC offset.\n\nReplacement for [`elm/time`'s `Time.here`](https://package.elm-lang.org/packages/elm/time/latest/Time#here).\n\n","type":"Web.Interface Time.Zone"}],"binops":[]},{"name":"Web.Window","comment":" Observe and alter the page's global environment as part of an [`Interface`](Web#Interface)\n\n@docs animationFrameListen, visibilityChangeListen\n@docs sizeRequest, resizeListen\n@docs preferredLanguagesRequest, preferredLanguagesChangeListen\n@docs documentListenTo, listenTo\n\nWhen navigating to a new page on the same site,\nyou may want to change the document's context:\n\n@docs titleReplaceBy, authorSet, keywordsSet, descriptionSet\n\n","unions":[],"aliases":[],"values":[{"name":"animationFrameListen","comment":" An [`Interface`](Web#Interface) for detecting when animation frames occur.\nThis will be about 60 times per second, though 75, 120, and 144 are also widely used.\nTo balance this out in your animation, the [current time](https://dark.elm.dmy.fr/packages/elm/time/latest/Time#Posix) is provided each frame.\n\nTo get a delta, you could use [`Web.Time.posixRequest`](Web-Time#posixRequest)\nto get a start time and check with e.g. [`Duration.from`](https://dark.elm.dmy.fr/packages/ianmackenzie/elm-units/latest/Duration#from) how far you've progressed in the timeline.\n\nNote: To improve performance and battery life, most browsers pause these notifications when the app is running in a background tab or a hidden `