Skip to content

Commit f2f298c

Browse files
kutyelkraklin
andauthored
Use Tailwind for styling instead of bootstrap (#2)
Co-authored-by: Tomáš Látal <latal.tomas@gmail.com>
1 parent a9d4aa1 commit f2f298c

File tree

13 files changed

+363
-125
lines changed

13 files changed

+363
-125
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Generate validating forms from JSON schemas.
1616
## Warnings
1717

1818
1. The way form fields are generated and presented is very opinionated and thus not always suitable for general case usage. This library is intended to be used for cases where you have control over how the schema is structured.
19-
2. The HTML that the library outputs is intended to be used together with [Bootstrap](https://getbootstrap.com/) to style the form. It can of course be used without Bootstrap but some field types might need some custom styling to look ok.
19+
2. The HTML that the library outputs is intended to be used together with [Tailwind CSS](https://tailwindcss.com/) to style the form. It can of course be used without Tailwind but some field types might need some custom styling to look ok.
2020
3. There is currently no support for linked schemas using `$ref`.
2121

2222
## Example usage

elm.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
"Json.Schema.Form.Encode",
1010
"Json.Schema.Form.Error",
1111
"Json.Schema.Form.Format",
12-
"Json.Schema.Form.Value"
12+
"Json.Schema.Form.Value",
13+
"Json.Schema.Form.Options",
14+
"Json.Schema.Form.Theme"
1315
],
1416
"elm-version": "0.19.0 <= v < 0.20.0",
1517
"dependencies": {

example/.tool-versions

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nodejs 20.8.1

example/Main.elm

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ import Form.Field exposing (FieldValue(..))
88
import Form.Input exposing (Input)
99
import Form.Validate
1010
import Html exposing (..)
11-
import Html.Attributes exposing (class, style)
11+
import Html.Attributes as Attrs exposing (class, style)
1212
import Html.Events exposing (onClick, onSubmit)
1313
import Json.Encode exposing (bool, float, int, list, string)
14-
import Json.Schema
1514
import Json.Schema.Builder exposing (..)
1615
import Json.Schema.Definitions
1716
import Json.Schema.Form exposing (Msg, State)
1817
import Json.Schema.Form.Encode
1918
import Json.Schema.Form.Error exposing (ErrorValue(..), Errors)
2019
import Json.Schema.Form.Format exposing (Format)
20+
import Json.Schema.Form.Theme as Theme exposing (Theme)
2121
import Regex
2222

2323

@@ -26,13 +26,100 @@ main =
2626
Browser.sandbox { init = init, update = update, view = view }
2727

2828

29+
tailwind : Theme
30+
tailwind =
31+
let
32+
theme =
33+
Theme.default
34+
35+
isInvalid =
36+
"border-2 border-red-500"
37+
in
38+
{ theme
39+
| -- inputs
40+
txt =
41+
\{ withError, format } ->
42+
Attrs.classList
43+
[ ( "block w-full rounded-md py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6", True )
44+
, ( "border-0", not withError )
45+
, ( isInvalid, withError )
46+
, case format of
47+
Just str ->
48+
( "format-" ++ str, True )
49+
50+
Nothing ->
51+
( "", False )
52+
]
53+
54+
-- checkbox
55+
, checkboxWrapper = Attrs.class "flex h-6 items-center"
56+
, checkboxInput =
57+
\{ withError } ->
58+
Attrs.classList
59+
[ ( "h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600", True )
60+
, ( isInvalid, withError )
61+
]
62+
, checkboxTitle = Attrs.class "ml-3 text-sm leading-6"
63+
64+
-- select
65+
, select =
66+
\{ withError } ->
67+
Attrs.classList
68+
[ ( "block w-full mt-2 rounded-md py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:max-w-xs sm:text-sm sm:leading-6", True )
69+
, ( "border-0", not withError )
70+
, ( isInvalid, withError )
71+
]
72+
73+
-- list group
74+
, listGroup = Attrs.class "mb-2"
75+
, listGroupItem = Attrs.class "border border-gray-300 rounded-md px-4 py-2 mb-2 shadow-sm"
76+
, listGroupAddItemButton = Attrs.class "rounded-md bg-gray-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-gray-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-600"
77+
, listGroupRemoveItemButton = Attrs.class "rounded-md bg-white px-2.5 py-1.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
78+
79+
-- tuple
80+
, formRow = Attrs.class "flex space-x-4"
81+
, formRowItem = Attrs.class "max-w-full flex-grow"
82+
83+
-- radio
84+
, radioWrapper = Attrs.class "flex items-center gap-x-3"
85+
, radioInput = Attrs.class "h-4 w-4 border-gray-300 text-indigo-600 focus:ring-indigo-600"
86+
, radioInputLabel = Attrs.class "block text-sm font-medium leading-6 text-gray-900"
87+
, field =
88+
\{ withError, withValue } ->
89+
Attrs.classList
90+
[ ( "mb-6", True )
91+
, ( "text-red-500", withError )
92+
, ( "has-value", withValue )
93+
]
94+
, fieldLabel = Attrs.class "block"
95+
, fieldInput = Attrs.class "field-input"
96+
, fieldInputMeta = Attrs.class "field-meta"
97+
, fieldTitle = Attrs.class "block text-sm font-medium leading-6 text-gray-900"
98+
, fieldDescription = Attrs.class "mt-2 text-sm leading-6 text-gray-600"
99+
, group =
100+
\{ withError, withValue } ->
101+
Attrs.classList
102+
[ ( "mb-4", True )
103+
, ( "text-red-500", withError )
104+
, ( "has-value", withValue )
105+
]
106+
, liveError = Attrs.class "text-red-500 text-xs my-2"
107+
, inputGroupPrepend = Attrs.class "inline-flex items-center rounded-l-md border border-r-0 border-gray-300 px-3 text-gray-500 sm:text-sm"
108+
, inputGroupPrependContent = Attrs.class "text-gray-500 sm:text-sm"
109+
, inputGroupAppend = Attrs.class "inline-flex items-center rounded-r-md border border-l-0 border-gray-300 px-3 text-gray-500 sm:text-sm"
110+
, inputGroupAppendContent = Attrs.class "text-gray-500 sm:text-sm"
111+
, inputGroup = Attrs.class "mt-2 flex shadow-sm"
112+
}
113+
114+
29115
init : State
30116
init =
31117
case schema of
32118
Ok schema_ ->
33119
Json.Schema.Form.init
34120
{ errors = errorString
35121
, formats = Dict.fromList formats
122+
, theme = tailwind
36123
}
37124
schema_
38125

@@ -49,7 +136,7 @@ view : State -> Html Msg
49136
view state =
50137
form [ onSubmit Json.Schema.Form.submit ]
51138
[ Json.Schema.Form.view state
52-
, button [ class "btn btn-primary" ] [ text "Submit" ]
139+
, button [ class "btn btn-primary rounded-md bg-blue-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600" ] [ text "Submit" ]
53140
, case Form.getOutput state.form of
54141
Just output ->
55142
let
@@ -221,7 +308,7 @@ schema =
221308
, ( "numbers"
222309
, buildSchema
223310
|> withType "array"
224-
|> withDefault (list float [ 6, 6.8 ])
311+
|> withDefault (list float [ 6, 7 ])
225312
|> withItems
226313
[ buildSchema
227314
|> withType "integer"

example/Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22
.PHONY : live
33

44
live:
5-
elm-live Main.elm --open --start-page=example.html -- --output=example.js
5+
npx elm-live Main.elm --open --start-page=example-tw.html -- --output=example-tw.js
6+
7+
bootstrap:
8+
npx elm-live Main.elm --open --start-page=example.html -- --output=example.js

example/elm.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@
44
".",
55
"../src"
66
],
7-
"elm-version": "0.19.0",
7+
"elm-version": "0.19.1",
88
"dependencies": {
99
"direct": {
1010
"elm/browser": "1.0.1",
1111
"elm/core": "1.0.2",
1212
"elm/html": "1.0.0",
1313
"elm/json": "1.1.2",
1414
"elm/regex": "1.0.0",
15+
"elm-community/html-extra": "3.4.0",
16+
"elmcraft/core-extra": "2.0.0",
1517
"etaque/elm-form": "4.0.0",
16-
"json-tools/json-schema": "1.0.2"
18+
"json-tools/json-schema": "1.0.2",
19+
"the-sett/elm-string-case": "1.0.2"
1720
},
1821
"indirect": {
1922
"NoRedInk/elm-json-decode-pipeline": "1.0.0",

example/example-tw.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>json-schema-form</title>
5+
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio,line-clamp"></script>
6+
<script src="example-tw.js"></script>
7+
</head>
8+
<body>
9+
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
10+
<div id="example"></div>
11+
</div>
12+
<script>
13+
Elm.Main.init({ node: document.getElementById("example") });
14+
</script>
15+
</body>
16+
</html>

example/example.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<html>
2+
<html>
33
<head>
44
<title>json-schema-form</title>
55
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
@@ -13,4 +13,4 @@
1313
Elm.Main.init({ node: document.getElementById("example") });
1414
</script>
1515
</body>
16-
</html>
16+
</html>

src/Json/Schema/Form.elm

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module Json.Schema.Form exposing
2-
( Options, State, Msg
2+
( State, Msg
33
, init, update
44
, view, submit
55
, getOutput
@@ -10,7 +10,7 @@ module Json.Schema.Form exposing
1010
1111
# Types
1212
13-
@docs Options, State, Msg
13+
@docs State, Msg
1414
1515
1616
# Init/update lifecycle
@@ -26,30 +26,17 @@ module Json.Schema.Form exposing
2626
2727
-}
2828

29-
import Dict exposing (Dict)
3029
import Form as F exposing (Msg)
3130
import Html exposing (Html)
3231
import Json.Schema.Definitions exposing (Schema)
3332
import Json.Schema.Form.Default exposing (default)
34-
import Json.Schema.Form.Error exposing (ErrorValue, Errors)
33+
import Json.Schema.Form.Error exposing (ErrorValue)
3534
import Json.Schema.Form.Fields
36-
import Json.Schema.Form.Format exposing (Format)
35+
import Json.Schema.Form.Options exposing (Options)
3736
import Json.Schema.Form.Validation exposing (validation)
3837
import Json.Schema.Form.Value exposing (Value)
3938

4039

41-
{-| Customize the generated form.
42-
43-
- `errors` - A function that turns error values into user readable strings.
44-
- `formats` - A list of custom formats (see `Json.Schema.Form.Format`).
45-
46-
-}
47-
type alias Options =
48-
{ errors : Errors
49-
, formats : Dict String Format
50-
}
51-
52-
5340
{-| The form state.
5441
-}
5542
type alias State =

0 commit comments

Comments
 (0)