Created
March 18, 2017 17:53
-
-
Save ohanhi/cb42ba2587fefbdae6962518176d114a to your computer and use it in GitHub Desktop.
A pure Elm auto expanding text area
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module AutoExpand exposing (main) | |
-- https://embed.ellie-app.com/Gnv9Bznh4na1/0 | |
import Html exposing (Html, div, p, br, textarea, text) | |
import Html.Attributes exposing (rows, style) | |
import Html.Events exposing (onInput, on) | |
import Json.Decode exposing (Decoder, field, at, map2, int, string) | |
type alias Model = | |
{ rows : Int | |
, inputText : String | |
} | |
type alias Config = | |
{ padding : Float | |
, lineHeight : Float | |
, minRows : Int | |
, maxRows : Int | |
} | |
config : Config | |
config = | |
{ padding = 10 | |
, lineHeight = 20 | |
, minRows = 1 | |
, maxRows = 4 | |
} | |
initModel : Model | |
initModel = | |
{ rows = config.minRows | |
, inputText = "" | |
} | |
type Msg | |
= NewValues String Int | |
update : Msg -> Model -> ( Model, Cmd Msg ) | |
update msg model = | |
case msg of | |
NewValues inputText height -> | |
( { model | |
| inputText = inputText | |
, rows = getRows height | |
} | |
, Cmd.none | |
) | |
view : Model -> Html Msg | |
view model = | |
div [ containerStyle ] | |
[ div | |
[ style [ ( "width", "200px" ) ] | |
] | |
[ textarea | |
[ on "input" inputDecoder | |
, rows model.rows | |
, Html.Attributes.value model.inputText | |
, textareaStyles model.rows | |
] | |
[] | |
, p [] | |
[ text ("Rows: " ++ toString model.rows) | |
, br [] [] | |
, text ("Min: " ++ toString config.minRows) | |
, br [] [] | |
, text ("Max: " ++ toString config.maxRows) | |
] | |
] | |
] | |
getRows : Int -> Int | |
getRows scrollHeight = | |
((toFloat scrollHeight - 2 * config.padding) / config.lineHeight) | |
|> ceiling | |
|> clamp config.minRows config.maxRows | |
inputDecoder : Decoder Msg | |
inputDecoder = | |
map2 NewValues | |
(at [ "target", "value" ] string) | |
(at [ "target", "scrollHeight" ] int) | |
containerStyle : Html.Attribute msg | |
containerStyle = | |
style | |
[ ( "background-color", "rebeccapurple" ) | |
, ( "color", "white" ) | |
, ( "font-family", "sans-serif" ) | |
, ( "width", "100vw" ) | |
, ( "height", "100vh" ) | |
, ( "display", "flex" ) | |
, ( "align-items", "center" ) | |
, ( "justify-content", "center" ) | |
, ( "flex-direction", "column" ) | |
] | |
textareaStyles : Int -> Html.Attribute msg | |
textareaStyles rowCount = | |
style | |
[ ( "padding", toString config.padding ++ "px" ) | |
, ( "border", "0 none" ) | |
, ( "border-radius", "2px" ) | |
, ( "box-sizing", "border-box" ) | |
, ( "line-height", toString config.lineHeight ++ "px" ) | |
, ( "width", "100%" ) | |
, ( "overflow" | |
, if rowCount <= config.maxRows then | |
"visible" | |
else | |
"scroll-y" | |
) | |
] | |
main : Program Never Model Msg | |
main = | |
Html.program | |
{ view = view | |
, update = update | |
, subscriptions = \_ -> Sub.none | |
, init = ( initModel, Cmd.none ) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment