[{"name":"Knob","comment":" Let's get started creating a control panel full of “knobs” to interactively\ntweak values in our application.\n\nWhen creating a knob, two considerations are important. The first is the type\nof the value you need to control. This package currently provides knobs for\nnumbers, strings, booleans, enumerated choices (custom types or anything like\nthat) and colors out of the box, and there is a way to either transform one into\nanother type ([`map`](#map)), or to create an entirely new knob\n([`custom`](#custom)).\n\nThe second important consideration is the interface you want to provide to\nmanipulate that value, i.e. the control itself. Many knobs offer different\ncontrols for the same type, particularly number-related ones, so pick the one\nthat best suits your needs!\n\n@docs Knob\n\n\n# Creating knobs for base values\n\nFirst up, within our app's `init` let's create a `Knob` and put it in the model.\nThe following are the functions you can use to create basic knobs that map to a\nsingle value.\n\n👀 Tip: Check the [**interactive documentation**][interactive-docs] to see\nworking examples of these!\n\n[interactive-docs]: https://agj.github.io/elm-knobs/2.0.0/\n\n@docs float, floatConstrained, floatSlider\n@docs int, intConstrained, intSlider\n@docs stringInput, stringTextarea\n@docs boolCheckbox\n@docs select, Color, colorPicker\n\n\n# Displaying\n\nThe next step is to actually display our knob in the page.\n\n@docs view, styles\n\n\n# Retrieving the value\n\nOf course, our knobs are of no use to us if we can't read the value entered by\nthe user.\n\n@docs value\n\n\n# Composing knobs\n\nMost of the time you'll want to control multiple values. For that purpose we're\ngoing to “stack” our knobs together.\n\n@docs compose, stack\n\n\n# Organization\n\nWe could have a bunch of similar knobs in our panel and not know what each of\nthem does, so let's make sure we do!\n\n@docs label, stackLabel\n\n\n# Transformation\n\n@docs map\n\n\n# Serialization\n\nThe value of your knobs will be reset every time you refresh the page, unless\nyou persist their value somehow. Knob serialization is a way to make it easier\nto do this using the Web Storage API or other such techniques. Check [this\nexample](https://github.com/agj/elm-knobs/blob/2.0.0/examples/web-storage/) to\nsee how to do it.\n\n@docs serialize, readSerialized\n\n\n# Custom knobs\n\n@docs custom\n\n","unions":[{"name":"Knob","comment":" Represents one user-interactive control mapped to one value of type `a`,\nwhich this package refers to as a “knob”.\nThis is the base type used to create your knobs control panel!\nNormally you'll have a single one of these stored in your model,\nbut that one knob can actually represent a group of [`compose`](#compose)d knobs.\n","args":["a"],"cases":[]}],"aliases":[{"name":"Color","comment":" Represents an RGB color value. Each channel value is a `Float` between 0 and 1.\nThis is the type that the [`colorPicker`](#colorPicker) knob uses.\n","args":[],"type":"{ red : Basics.Float, green : Basics.Float, blue : Basics.Float }"}],"values":[{"name":"boolCheckbox","comment":" Creates a checkbox representing a boolean value.\n`initial` determines whether it will be initially checked or not.\n","type":"Basics.Bool -> Knob.Knob Basics.Bool"},{"name":"colorPicker","comment":" Creates a color picker input.\nColors are represented using a type alias `Color`,\nwhich is easily [`map`](#map)pable into other color formats for your convenience.\nBelow is an example mapping it into [avh4/elm-color](https://package.elm-lang.org/packages/avh4/elm-color/1.0.0/) format.\n\n    -- We set magenta as the initial color.\n    Knob.colorPicker { red = 1, green = 0, blue = 1 }\n        -- We map it into avh4/elm-color format.\n        |> Knob.map (\\c -> Color.rgb c.red c.green c.blue)\n\n","type":"Knob.Color -> Knob.Knob Knob.Color"},{"name":"compose","comment":" Creates a knob that joins multiple knobs to build up a record\n(or actually any data structure you want, depending on the `constructor` argument you pass it!)\n\nPipe ([`|>`](https://package.elm-lang.org/packages/elm/core/1.0.5/Basics#%7C%3E)) the knobs into it\nusing [`stack`](Knob#stack) or [`stackLabel`](Knob#stackLabel) in order to provide the arguments.\n\n    type alias Controls =\n        { someNumber : Float\n        , anInteger : Int\n        }\n\n    aKnob =\n        Knob.compose Controls\n            -- This knob will map to `someNumber`:\n            |> Knob.stack (Knob.float { step = 1, initial = 0 })\n            -- This one will map to `anInteger`:\n            |> Knob.stack (Knob.int { step = 1, initial = 0 })\n\nHere's how you use it to build up a different data structure, in this case a tuple.\nNotice that the number of arguments in the function matches the number of “stacks”.\n\n    anotherKnob =\n        Knob.compose (\\theFloat theInt -> ( theFloat, theInt ))\n            |> Knob.stack (Knob.float { step = 1, initial = 0 })\n            |> Knob.stack (Knob.int { step = 1, initial = 0 })\n\n","type":"(a -> b) -> Knob.Knob (a -> b)"},{"name":"custom","comment":" Creates a knob for any type, using a custom HTML view that you supply.\nYou can use this function if there is some kind of knob you need that is not\navailable in this package, and can't be created by using [`map`](#map) over a\npredefined knob.\n\nKnobs are comprised of a `value` of the appropriate type, and a `view` which\nlistens to user input (typically the `Html.Events.onInput` event) and emits the\nupdated knob, instead of a regular message like is normally done. In this sense,\nknobs are recursive, as their view needs to construct a new knob, typically by\ncalling the very same constructor function that created it in the first place.\n\n\n## Basic use\n\nHere's how the `boolCheckbox` knob would be created using `custom`:\n\n    ourBoolKnob : Bool -> Knob Bool\n    ourBoolKnob initial =\n        let\n            view : () -> Html (Knob Bool)\n            view () =\n                Html.input\n                    [ Html.Attributes.type_ \"checkbox\"\n                    , Html.Attributes.checked initial\n                    , Html.Events.onCheck ourBoolKnob\n                    ]\n                    []\n        in\n        Knob.custom\n            { value = initial\n            , view = view\n            , serialization = Nothing\n            }\n\n(Ignore the `serialization` part for now.)\n\nNotice how `view` is a thunk—that is, a function that takes `()` (a placeholder\nvalue) and returns the view. The view is just some HTML that emits knobs instead\nof messages. Take a look at the line with `Html.Events.onCheck` and make note\nof what we're doing: We're directly passing in `ourBoolKnob` because it's a\nfunction that takes the new “checked” value and with it constructs the knob\nanew. This is how we're transforming the contained value when the user clicks.\n\n\n## Making it serializable\n\nIf you need to [serialize](Knob#serialize) your knob, you'll need to take care\nof that by setting the `serialization` field in the configuration record. You'll\nneed [`elm/json`](https://package.elm-lang.org/packages/elm/json/latest/) for\nthis.\n\nThis is a record wrapped in `Maybe`, with an `encode` function which should\nreturn the current value converted into a `Json.Encode.Value`, and a `decoder`\nof type `Json.Decode.Decoder` that reconstructs the whole knob out of a value\ncreated by `encode`. It's easy to get this pair wrong, so make sure you test\nserializing and deserializing!\n\nThis would work for the above `ourCustomBool` example:\n\n    Just\n        { encode = \\() -> Json.Encode.bool initial\n        , decoder = Json.Decode.map ourCustomBool Json.Decode.bool\n        }\n\n\n## Keep raw user input and parsed output values separate!\n\nBe careful! If you don't have experience writing forms in Elm, there's a very\ncommon pitfall you have to be aware of: When taking unconstrained user input,\nyou can wind up making it so that the user cannot input freely. This occurs when\nwe parse the input into a different type in a lossy manner. For example, if the\ninput is through typing in a text field, and we convert that into a custom type,\nthe user might not be able to actually finish typing.\n\nLet's imagine we want to display a text field to map a `String` to a `Vegetable`\ntype. In the naïve case, our knob's signature could look like this, taking\n`Vegetable` to set the initial value:\n\n    vegetableKnob : Vegetable -> Knob Vegetable\n\nIt would convert the initial value to a `String`, and set that as the text\nfield's text. Then, upon user input, we'd parse the input `String` into our\ntype, and use that to construct the updated knob.\n\nThe problem with this situation is that if the conversion from `String` to\n`Vegetable` and then back into `String` is lossy (i.e., the result is not the\nsame as what the user typed,) then the user won't be able to finish typing some\nthings, as they won't be valid in their incomplete form.\n\nSay we use this function to parse the raw input into `Vegetable`:\n\n    vegetableFromString : String -> Vegetable\n    vegetableFromString text =\n        case text of\n            \"carrot\" ->\n                Carrot\n\n            _ ->\n                Tomato\n\nIf the user wants to type “carrot”, and starts typing “c”, since `\"c\"` is not\n(yet) a valid value, it will be parsed as `Tomato` and the text field's text\nwill be reset to whatever the string value for `Tomato` is.\n\nIn order to prevent this behavior, take the raw, unparsed `String` as the text\nfield's `value` property, and set the parsed result as the knob's `value`. This\nmeans that your knob will need to take a `String` as its initial value, and not\na `Vegetable`!\n\n    vegetableKnob : String -> Knob Vegetable\n    vegetableKnob initial =\n        Knob.custom\n            { -- Parse here!\n              value = vegetableFromString initial\n            , view =\n                \\() ->\n                    Html.input\n                        [ Html.Attributes.type_ \"text\"\n\n                        -- No parsing.\n                        , Html.Attributes.value initial\n                        , Html.Events.onInput vegetableKnob\n                        ]\n                        []\n            , serialization = Nothing\n            }\n\n","type":"{ value : a, view : () -> Html.Html (Knob.Knob a), serialization : Maybe.Maybe { encode : () -> Json.Encode.Value, decoder : Json.Decode.Decoder (Knob.Knob a) } } -> Knob.Knob a"},{"name":"float","comment":" Creates an input field knob for manually entering any floating point number.\nThe `step` argument specifies the amount the number will increase or decrease\nwhen pressing the up and down keys.\n`initial` is just the value it takes on first load.\n","type":"{ step : Basics.Float, initial : Basics.Float } -> Knob.Knob Basics.Float"},{"name":"floatConstrained","comment":" Creates an input field knob for manually entering numbers within a specific range,\nwhere `range = ( min, max )`.\nThe `step` argument specifies the amount the number will increase or decrease\nwhen pressing the up and down keys.\n`initial` is just the value it takes on first load.\n","type":"{ range : ( Basics.Float, Basics.Float ), step : Basics.Float, initial : Basics.Float } -> Knob.Knob Basics.Float"},{"name":"floatSlider","comment":" Creates a slider knob useful for quickly tweaking numbers when precision is not needed.\nRequires a `range = ( min, max )` to set the boundaries of the slider control.\n`initial` is just the value it takes on first load.\n\nThe `step` argument indicates the granularity of the values the slider will allow,\nso a step of `1` will produce a slider that jumps between values like `1`, `2`, `3` as you slide it to the right,\nwhereas a step of `0.1` will produce one that allows setting values like `1.1` or `2.5`.\n\n","type":"{ range : ( Basics.Float, Basics.Float ), step : Basics.Float, initial : Basics.Float } -> Knob.Knob Basics.Float"},{"name":"int","comment":" Creates an input field knob for manually entering any integer.\nThe `step` argument specifies the amount the number will increase or decrease\nwhen pressing the up and down keys.\n`initial` is just the value it takes on first load.\n","type":"{ step : Basics.Int, initial : Basics.Int } -> Knob.Knob Basics.Int"},{"name":"intConstrained","comment":" Creates an input field knob for manually entering integers within a specific range.\nThe `step` argument specifies the amount the number will increase or decrease\nwhen pressing the up and down keys.\n`initial` is just the value it takes on first load.\n","type":"{ range : ( Basics.Int, Basics.Int ), step : Basics.Int, initial : Basics.Int } -> Knob.Knob Basics.Int"},{"name":"intSlider","comment":" Creates a slider knob useful for quickly tweaking integers when precision is not needed.\nRequires a `range = ( min, max )` to set the boundaries of the slider control.\n`initial` is just the value it takes on first load.\n\nThe `step` argument indicates the granularity of the values the slider will allow,\nso a step of `1` will produce a slider that will set on any integer value as you slide it to the right,\nwhereas a step of `10` will produce one that makes bigger jumps between `10`, `20`, `30`, etc.\n\n","type":"{ range : ( Basics.Int, Basics.Int ), step : Basics.Int, initial : Basics.Int } -> Knob.Knob Basics.Int"},{"name":"label","comment":" Attaches a text description next to a knob, as a way to identify what the control is for.\n\nThe following example will produce a [`float`](Knob#float) knob described as “x position”.\n\n    Knob.label \"x position\"\n        (Knob.float { step = 1, initial = 0 })\n\n","type":"String.String -> Knob.Knob a -> Knob.Knob a"},{"name":"map","comment":" Analogous to `List.map` or other data structures' `map` function,\nyou can use this function to convert the value produced by a Knob.\n\nThe following example converts a knob that produces an `Int` (i.e. a `Knob Int`)\ninto one that produces a `String` (i.e. a `Knob String`.) This is achieved\nbecause `String.fromInt` is a function with the type `Int -> String`.\n\n    Knob.int { step = 1, initial = 0 }\n        |> Knob.map String.fromInt\n\n","type":"(a -> b) -> Knob.Knob a -> Knob.Knob b"},{"name":"readSerialized","comment":" After you have used [`serialize`](Knob#serialize) to store your knob's value\nsomewhere, the way to get that value back into the knob is this function. You'll\nprobably want to use it on `init` with the serialized data you get from flags.\n\nIf this function fails to interpret the passed value, the knob will just\nretain its initial value. It works with single, [composed](Knob#compose) and\n[mapped](Knob#map) knobs. For [custom](Knob#custom) knobs it will only work if\n`serialization` was properly defined when created.\n\nNotice that you need to create your knob with initial values normally,\nand as a last step use this function to update it with the serialized value.\n\n    init serializedKnob =\n        ( { knob =\n                Knob.int { step = 1, init = 0 }\n                    |> readSerialized serializedKnob\n          }\n        , Cmd.none\n        )\n\n","type":"Json.Encode.Value -> Knob.Knob a -> Knob.Knob a"},{"name":"select","comment":" Creates a dropdown select input for a custom type or arbitrary values of any\ntype you wish. You'll need to provide a `List` mapping unique strings (options\nin the dropdown) to values of your type.\n\nHere's a simple example mapping `\"yes\"` and `\"no\"` options to `Bool` values:\n\n    Knob.select\n        { options =\n            [ ( \"yes\", True )\n            , ( \"no\", False )\n            ]\n        , initial = False\n        }\n\n","type":"{ options : List.List ( String.String, a ), initial : a } -> Knob.Knob a"},{"name":"serialize","comment":" Convert a knob's value into an [`elm/json`](https://package.elm-lang.org/packages/elm/json/) `Value`.\nYou can then send this out to JavaScript via a port,\nand store it using the browser's [Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API),\nfor example. You'll want to use in your update function whenever you get\nan updated knob.\n\n    port saveKnobState : Json.Encode.Value -> Cmd msg\n\n    update msg model =\n        case msg of\n            KnobUpdated updatedKnob ->\n                ( { model | knob = updatedKnob }\n                , saveKnobState (Knob.serialize updatedKnob)\n                )\n\n","type":"Knob.Knob a -> Json.Encode.Value"},{"name":"stack","comment":" Adds a knob into a [`compose`](Knob#compose) knob.\nSee the documentation for that for an example.\n\nThis function is called “stack” because the order you compose your knobs does matter,\nas they will be displayed one on top of the other!\n\n","type":"Knob.Knob a -> Knob.Knob (a -> b) -> Knob.Knob b"},{"name":"stackLabel","comment":" Convenience function that unifies the functionality of [`stack`](Knob#stack) and [`label`](Knob#label).\n\nThe two examples below produce the same identical result:\n\n    -- This:\n    Knob.stackLabel \"Some label\" someKnob\n\n    -- is the same as:\n    Knob.stack (Knob.label \"Some label\" someKnob)\n\n","type":"String.String -> Knob.Knob a -> Knob.Knob (a -> b) -> Knob.Knob b"},{"name":"stringInput","comment":" Creates a small, single-line input field knob for entering text.\n`initial` is the text it will be prefilled with.\n","type":"String.String -> Knob.Knob String.String"},{"name":"stringTextarea","comment":" Creates a multiline input field knob for entering text.\nYou can specify the dimensions of this control by setting the amount of `columns` and `rows`.\n`initial` is the text it will be prefilled with.\n","type":"{ columns : Maybe.Maybe Basics.Int, rows : Maybe.Maybe Basics.Int, initial : String.String } -> Knob.Knob String.String"},{"name":"styles","comment":" Default styles for the knobs, provided as a `<style>` tag.\nPut this as a child somewhere in your view in order to use them.\n\nYou could choose not to use these default styles and instead provide your own.\nI recommend you check the DOM output in your browser's inspector—the structure of the HTML produced is pretty simple!\n\n","type":"Html.Html msg"},{"name":"value","comment":" Extract the current value out of a knob.\nUse it in your view to affect what you display.\n\n    Knob.int { step = 1, initial = 5 }\n        |> Knob.value -- Gets `5`.\n\n","type":"Knob.Knob a -> a"},{"name":"view","comment":" Converts a knob into HTML to put in your view. You should display a single\n[`Knob`](Knob#Knob) value at any which time, so if you need multiple knobs, make\nsure you [`compose`](Knob#compose) them!\n\nKnobs keep track of their state once they're put in the view, but for that you\nneed to wire them up with a message, which is the second argument that this\nfunction takes.\n\nThis function produces plain HTML with no styles, so make sure you also include\n[`styles`](Knob#styles) in your page to make it display properly, or provide\nyour own custom styles.\n\n    -- Prepare a message for your knob:\n    type Msg =\n        KnobUpdated (Knob YourType)\n\n    -- Put this as an HTML node within your view:\n    Knob.view [] KnobUpdated yourKnob\n\nCheck [the documentation's readme](https://package.elm-lang.org/packages/agj/elm-knobs/2.0.0/)\nfor a full demonstration on how to wire things up.\n\nBy default, it puts the panel in the lower-left corner of the viewport,\nhidden until you hover over its icon. However, `view` takes a list of options\nthat change the way the knobs panel is rendered, which you can find in the\n[`Knob.Option`](Knob-Option) module. Be aware that these options may only change\nthe CSS classes that are added to the HTML, so if you don't use [the provided\nstyles](#styles), the effect might not be what you expected.\n\n","type":"List.List Knob.Option.Option -> (Knob.Knob a -> msg) -> Knob.Knob a -> Html.Html msg"}],"binops":[]},{"name":"Knob.Option","comment":"\n\n@docs Option\n\n\n# Anchoring\n\nOptions that determine where in the page the knobs panel will be placed.\n\n@docs anchorBottomLeft, anchorBottomRight, anchorTopLeft, anchorTopRight\n@docs detached\n\n","unions":[],"aliases":[{"name":"Option","comment":" An option that [`Knob.view`](Knob#view) receives, which changes how the\nknobs panel is rendered.\n","args":[],"type":"Internal.Option.Option"}],"values":[{"name":"anchorBottomLeft","comment":" Sticks the knobs panel to the bottom-left corner of the viewport. This is the\ndefault placement.\n","type":"Knob.Option.Option"},{"name":"anchorBottomRight","comment":" Sticks the knobs panel to the bottom-right corner of the viewport.\n","type":"Knob.Option.Option"},{"name":"anchorTopLeft","comment":" Sticks the knobs panel to the top-left corner of the viewport.\n","type":"Knob.Option.Option"},{"name":"anchorTopRight","comment":" Sticks the knobs panel to the top-right corner of the viewport.\n","type":"Knob.Option.Option"},{"name":"detached","comment":" Makes the panel not fixed to a corner of the viewport, but instead render\nwithin the flow of the DOM, always visible.\n","type":"Knob.Option.Option"}],"binops":[]}]