Skip to content
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,19 @@ Generate validating forms from JSON schemas.
- Categorization Example
- Implement prev/next buttons
- Implement stepper variant

# Changelog

## 2.0.0

* Produce an intermediate representation instead of the HTML view. This allows much richer view customization.
* A default Tailwind view function is available. It can be used as a starting point for a custom view implementation.
* Display errors on fields only after they have been touched, or after a submit was triggered.
* Trim text fields

## 1.0.0

- Can handle most of the UI Schema specification
- Can handle almost all JSON Schema features (draft-04 and draft-06).
- Generates all common types of input fields (`text`, `select`, etc.) with optional labels and descriptions.
- Comes with default Tailwind CSS theme in the `Theme` object that can be customised.
4 changes: 2 additions & 2 deletions elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
"name": "scrive/elm-json-forms",
"summary": "JSON Forms Implementation in Elm.",
"license": "MIT",
"version": "1.0.0",
"version": "2.0.0",
"exposed-modules": [
"Form",
"Form.Widget",
"Form.Error",
"Form.Theme",
"Json.Pointer",
"UiSchema"
],
Expand Down
102 changes: 71 additions & 31 deletions example/src/Main.elm
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Main exposing (main)

import Browser
import Browser.Navigation as Nav
import Cmd.Extra as Cmd
import Examples exposing (exampleForms)
import Form exposing (Form)
import Html exposing (..)
Expand All @@ -15,7 +16,6 @@ import Json.Schema
import List.Extra as List
import Maybe.Extra as Maybe
import Model exposing (..)
import Settings
import UiSchema
import Url
import Url.Parser
Expand Down Expand Up @@ -47,11 +47,16 @@ update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
ExampleMsg i m ->
( { model
| forms = List.updateAt i (updateExample m) model.forms
}
, Cmd.none
)
case List.getAt i model.forms |> Maybe.map (updateExample m) of
Nothing ->
( model, Cmd.none )

Just ( st, cmd ) ->
( { model
| forms = List.updateAt i (always st) model.forms
}
, Cmd.map (ExampleMsg i) cmd
)

UrlChanged url ->
case parseUrl url of
Expand Down Expand Up @@ -80,46 +85,55 @@ parseUrl url =
Maybe.join <| Url.Parser.parse (Url.Parser.query <| Url.Parser.Query.int "example") { url | path = "" }


updateExample : ExampleMsg -> FormState -> FormState
updateExample : ExampleMsg -> FormState -> ( FormState, Cmd ExampleMsg )
updateExample msg fs =
case msg of
FormMsg formMsg ->
{ fs | form = Maybe.map (Form.update formMsg) fs.form }
( { fs | form = Maybe.map (Form.update formMsg) fs.form }, Cmd.none )

EditSchema s ->
case Json.Schema.fromString s of
Ok schema ->
{ fs
( { fs
| stringSchema = s
, form = Maybe.map (Form.setSchema schema) fs.form
, schemaError = Nothing
}
}
, Cmd.none
)

Err e ->
{ fs
( { fs
| stringSchema = s
, schemaError = Just e
}
}
, Cmd.none
)

Submit ->
( fs, Cmd.perform (FormMsg Form.validateAllFieldsMsg) )

EditUiSchema s ->
case UiSchema.fromString s of
Ok uiSchema ->
{ fs
( { fs
| stringUiSchema = Just s
, form = Maybe.map (Form.setUiSchema (Just uiSchema)) fs.form
, uiSchemaError = Nothing
}
}
, Cmd.none
)

Err e ->
{ fs
( { fs
| stringUiSchema = Just s
, uiSchemaError = Just e
}
}
, Cmd.none
)

SwitchTab t ->
{ fs
| tab = t
}
( { fs | tab = t }, Cmd.none )


view : Model -> Browser.Document Msg
Expand Down Expand Up @@ -179,12 +193,19 @@ viewExample fs =

Just form ->
div [ class "border shadow rounded p-3 bg-white" ]
[ Html.map FormMsg (Form.view form) ]
[ Html.map FormMsg (Form.viewWidget (Form.widget form))
, button
[ Attrs.class "bg-blue-500 text-white p-2 rounded"
, Events.onClick Submit
]
[ text "Validate" ]
]
]
]
, div [ class "w-full lg:w-1/2 px-2" ]
[ div [ class "border-b mb-3" ]
[ viewTabHeader [] fs.tab DataTab
[ viewTabHeader [] fs.tab RawDataTab
, viewTabHeader [] fs.tab SubmitDataTab
, viewTabHeader
[ if fs.schemaError /= Nothing then
class "line-through"
Expand All @@ -205,8 +226,11 @@ viewExample fs =
UiSchemaTab
]
, div []
[ div [ Attrs.hidden (fs.tab /= DataTab) ]
[ Html.viewMaybe viewData fs.form
[ div [ Attrs.hidden (fs.tab /= RawDataTab) ]
[ Html.viewMaybe viewRawData fs.form
]
, div [ Attrs.hidden (fs.tab /= SubmitDataTab) ]
[ Html.viewMaybe viewSubmitData fs.form
]
, div [ Attrs.hidden (fs.tab /= JsonSchemaTab) ]
[ textarea [ Attrs.name "JsonSchema", Events.onInput EditSchema, Attrs.rows 30 ] fs.stringSchema
Expand Down Expand Up @@ -245,8 +269,11 @@ viewTabHeader attrs activeTab tab =
)
[ text <|
case tab of
DataTab ->
"Data"
RawDataTab ->
"Raw Data"

SubmitDataTab ->
"Submit Data"

JsonSchemaTab ->
"JSON Schema"
Expand All @@ -269,14 +296,27 @@ viewError title err =
]


viewData : Form -> Html a
viewData form =
let
dataText =
Encode.encode 4 (Form.getValue form)
viewRawData : Form -> Html a
viewRawData form =
viewData form <| Encode.encode 4 <| Form.getRawValue form


viewSubmitData : Form -> Html a
viewSubmitData form =
viewData form <|
case Form.getSubmitValue form of
Nothing ->
"<empty>"

Just v ->
Encode.encode 4 v


viewData : Form -> String -> Html a
viewData form dataText =
let
errorsText =
String.join "\n" (List.map (\( pointer, err ) -> Pointer.toString pointer ++ ": " ++ Settings.errorString err) <| Form.getErrors form)
String.join "\n" (List.map (\( pointer, err ) -> Pointer.toString pointer ++ ": " ++ Form.errorString err) <| Form.getErrors form)
in
div []
[ textarea [ Attrs.id "Data", Attrs.readonly True, Attrs.rows 15 ] dataText
Expand Down
18 changes: 11 additions & 7 deletions example/src/Model.elm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import Browser.Navigation as Nav
import Form exposing (Form)
import Json.Schema
import Result.Extra as Result
import Settings
import UiSchema
import Url

Expand All @@ -22,7 +21,8 @@ type alias FormState =


type Tab
= DataTab
= RawDataTab
| SubmitDataTab
| JsonSchemaTab
| UiSchemaTab

Expand All @@ -42,6 +42,7 @@ type Msg

type ExampleMsg
= FormMsg Form.Msg
| Submit
| EditSchema String
| EditUiSchema String
| SwitchTab Tab
Expand All @@ -55,12 +56,15 @@ makeForm title stringSchema stringUiSchema =

uiSchema =
Maybe.map UiSchema.fromString stringUiSchema

options =
Form.defaultOptions
in
case ( schema, uiSchema ) of
( Ok s, Nothing ) ->
{ title = title
, form = Just <| Settings.initForm title s Nothing
, tab = DataTab
, form = Just <| Form.init options title s Nothing
, tab = RawDataTab
, stringSchema = stringSchema
, stringUiSchema = Nothing
, schemaError = Nothing
Expand All @@ -69,8 +73,8 @@ makeForm title stringSchema stringUiSchema =

( Ok s, Just (Ok us) ) ->
{ title = title
, form = Just <| Settings.initForm title s (Just us)
, tab = DataTab
, form = Just <| Form.init options title s (Just us)
, tab = RawDataTab
, stringSchema = stringSchema
, stringUiSchema = stringUiSchema
, schemaError = Nothing
Expand All @@ -80,7 +84,7 @@ makeForm title stringSchema stringUiSchema =
( s, us ) ->
{ title = title
, form = Nothing
, tab = DataTab
, tab = RawDataTab
, stringSchema = stringSchema
, stringUiSchema = stringUiSchema
, schemaError = Result.error s
Expand Down
94 changes: 0 additions & 94 deletions example/src/Settings.elm

This file was deleted.

Loading