Skip to content

Commit 377e94e

Browse files
committed
Required field indication
1 parent c4d9b31 commit 377e94e

File tree

9 files changed

+235
-181
lines changed

9 files changed

+235
-181
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ Development progress:
1919
- [x] editing of number and boolean
2020
- [x] customizable widgets
2121
- [x] password field
22+
- [x] mark required fields with *
2223

2324
Next steps will be some of those (not necessarily in this order):
2425

2526
- [ ] radiogroup widget for enum
26-
- [ ] required and optional field
27+
- [ ] optional field indication (configurable alternative to required)
2728
- [ ] dealing with `undefined` (erase property)
2829
- [ ] multiline editing
2930
- [ ] editing as json

src/Demo.elm

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ content : Model -> Html Msg
106106
content model =
107107
let
108108
jsonSchema =
109-
div [ style [ ( "width", "50%" ), ( "vertical-align", "top" ), ( "display", "inline-block" ), ( "min-width", "300px" ), ( "overflow", "auto" ) ] ]
110-
[ h4 [] [ text <| "Json Schema" ]
109+
div [ style [ ( "width", "50%" ), ( "vertical-align", "top" ), ( "display", "inline-block" ), ( "min-width", "300px" ), ( "max-width", "80ch" ), ( "overflow", "auto" ) ] ]
110+
[ h4 [] [ text <| "JSON Schema" ]
111111
, pre [ style [ ( "line-height", "1.3" ) ] ] [ getSnippet model.showcase |> Json.Schema.Definitions.encode |> Json.Encode.encode 4 |> text ]
112112
]
113113

src/Json/Form.elm

+18-156
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ module Json.Form
99
)
1010

1111
import Html exposing (..)
12-
import Html.Attributes exposing (..)
13-
import Html.Events exposing (..)
12+
import Json.Form.UiSpec as UiSpec
1413
import Json.Form.Definitions as Definitions exposing (Path, EditingMode(..), Msg(..))
1514
import Json.Schema.Definitions exposing (..)
1615
import Json.Schema
@@ -20,7 +19,7 @@ import Json.Decode as Decode exposing (decodeValue)
2019
import ErrorMessages exposing (stringifyError)
2120
import Dict exposing (Dict)
2221
import Json.Form.TextField as TextField
23-
import Json.Form.Helper as Helper
22+
import Json.Form.Selection as Selection
2423
import Util exposing (..)
2524

2625

@@ -44,26 +43,26 @@ init =
4443

4544
view : Model -> Html Msg
4645
view model =
47-
viewNode model model.schema []
46+
viewNode model model.schema False []
4847

4948

50-
viewNode : Model -> Schema -> Path -> Html Msg
51-
viewNode model schema path =
49+
viewNode : Model -> Schema -> Bool -> Path -> Html Msg
50+
viewNode model schema isRequired path =
5251
case editingMode model schema of
5352
TextField ->
54-
TextField.view model schema path
53+
TextField.view model schema isRequired path
5554

5655
NumberField ->
57-
viewNumericTextField model schema path
56+
TextField.viewNumeric model schema isRequired path
5857

5958
Switch ->
60-
viewSwitch model schema path
59+
Selection.switch model schema isRequired path
6160

6261
Checkbox ->
63-
viewCheckbox model schema path
62+
Selection.checkbox model schema isRequired path
6463

6564
Object ->
66-
viewObject model schema path
65+
viewObject model schema isRequired path
6766

6867
_ ->
6968
text "Not implemented"
@@ -95,154 +94,22 @@ editingMode model schema =
9594

9695
getBooleanUiWidget : Schema -> EditingMode
9796
getBooleanUiWidget schema =
98-
schema
99-
|> getCustomKeywordValue "ui"
100-
|> Maybe.andThen
101-
(\settings ->
102-
settings
103-
|> Decode.decodeValue
104-
(Decode.field "widget" Decode.string
105-
|> Decode.map
106-
(\widget ->
107-
if widget == "switch" then
108-
Switch
109-
else
110-
Checkbox
111-
)
112-
)
113-
|> Result.toMaybe
114-
)
115-
|> Maybe.withDefault Checkbox
116-
117-
118-
viewSwitch : Model -> Schema -> Path -> Html Msg
119-
viewSwitch model schema path =
120-
let
121-
isChecked =
122-
case model.value |> Maybe.andThen (JsonValue.getIn path >> Result.toMaybe) of
123-
Just (BoolValue x) ->
124-
x
125-
126-
_ ->
127-
False
97+
case schema |> getUiSpec of
98+
UiSpec.Switch ->
99+
Switch
128100

129-
( hasError, helperText ) =
130-
Helper.view model schema path
131-
in
132-
label
133-
[ classList
134-
[ ( "jf-switch", True )
135-
, ( "jf-switch--on", isChecked )
136-
, ( "jf-switch--focused", model.focused |> Maybe.map ((==) path) |> Maybe.withDefault False )
137-
, ( "jf-switch--invalid", hasError )
138-
]
139-
]
140-
[ input
141-
[ type_ "checkbox"
142-
, class "jf-switch__input"
143-
, checked isChecked
144-
, onFocus <| FocusInput (Just path)
145-
, onBlur <| FocusInput Nothing
146-
, onCheck <| (JsonValue.BoolValue >> EditValue path)
147-
]
148-
[]
149-
, span [ class "jf-switch__label" ] [ schema |> getTitle |> text ]
150-
, div [ class "jf-switch__track" ] []
151-
, div [ class "jf-switch__thumb" ] []
152-
, div [ class "jf-switch__helper-text" ] [ helperText ]
153-
]
154-
155-
156-
viewCheckbox : Model -> Schema -> Path -> Html Msg
157-
viewCheckbox model schema path =
158-
let
159-
isChecked =
160-
case model.value |> Maybe.andThen (JsonValue.getIn path >> Result.toMaybe) of
161-
Just (BoolValue x) ->
162-
x
101+
_ ->
102+
Checkbox
163103

164-
_ ->
165-
False
166104

167-
( hasError, helperText ) =
168-
Helper.view model schema path
169-
in
170-
label
171-
[ classList
172-
[ ( "jf-checkbox", True )
173-
, ( "jf-checkbox--on", isChecked )
174-
, ( "jf-checkbox--focused", model.focused |> Maybe.map ((==) path) |> Maybe.withDefault False )
175-
, ( "jf-checkbox--invalid", hasError )
176-
]
177-
]
178-
[ input
179-
[ type_ "checkbox"
180-
, class "jf-checkbox__input"
181-
, checked isChecked
182-
, onFocus <| FocusInput (Just path)
183-
, onBlur <| FocusInput Nothing
184-
, onCheck <| (JsonValue.BoolValue >> EditValue path)
185-
]
186-
[]
187-
, span [ class "jf-checkbox__label" ] [ schema |> getTitle |> text ]
188-
, div [ class "jf-checkbox__box-outline" ]
189-
[ div [ class "jf-checkbox__tick-outline" ] []
190-
]
191-
, div [ class "jf-checkbox__helper-text" ] [ helperText ]
192-
]
193-
194-
195-
viewNumericTextField : Model -> Schema -> Path -> Html Msg
196-
viewNumericTextField model schema path =
197-
let
198-
isFocused =
199-
model.focused
200-
|> Maybe.map ((==) path)
201-
|> Maybe.withDefault False
202-
203-
editedValue =
204-
if isFocused then
205-
model.editedNumber
206-
else
207-
model.value
208-
|> Maybe.map (JsonValue.getIn path)
209-
|> Maybe.andThen Result.toMaybe
210-
|> Maybe.map Util.jsonValueToString
211-
|> Maybe.withDefault ""
212-
213-
( hasError, helperText ) =
214-
Helper.view model schema path
215-
in
216-
div
217-
[ classList
218-
[ ( "jf-textfield", True )
219-
, ( "jf-textfield--focused", isFocused )
220-
, ( "jf-textfield--empty", editedValue == "" )
221-
, ( "jf-textfield--invalid", hasError )
222-
]
223-
]
224-
[ input
225-
[ class "jf-textfield__input"
226-
, onFocus <| FocusNumericInput (Just path)
227-
, onBlur <| FocusNumericInput Nothing
228-
, onInput <| EditNumber
229-
, value <| editedValue
230-
, type_ "number"
231-
]
232-
[]
233-
, label [ class "jf-textfield__label" ] [ schema |> getTitle |> text ]
234-
, div [ class "jf-textfield__helper-text" ] [ helperText ]
235-
]
236-
237-
238-
viewObject : Model -> Schema -> Path -> Html Msg
239-
viewObject model schema path =
105+
viewObject : Model -> Schema -> Bool -> Path -> Html Msg
106+
viewObject model schema isRequired path =
240107
let
241108
iterateOverSchemata propsDict required (Schemata schemata) =
242109
schemata
243110
|> List.map
244111
(\( propName, subSchema ) ->
245-
viewNode model subSchema (path ++ [ propName ])
112+
viewNode model subSchema (required |> Maybe.withDefault [] |> List.member propName) (path ++ [ propName ])
246113
)
247114
in
248115
case schema of
@@ -373,8 +240,3 @@ dictFromListErrors list =
373240
)
374241
)
375242
Dict.empty
376-
377-
378-
(=>) : a -> b -> ( a, b )
379-
(=>) a b =
380-
( a, b )

src/Json/Form/Selection.elm

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
module Json.Form.Selection exposing (checkbox, switch)
2+
3+
import Json.Form.Definitions exposing (..)
4+
import Json.Schema.Definitions exposing (Schema, getCustomKeywordValue)
5+
import Html exposing (..)
6+
import Html.Attributes exposing (..)
7+
import Html.Events exposing (onFocus, onBlur, onInput, onCheck)
8+
import JsonValue exposing (JsonValue(BoolValue))
9+
import Util exposing (..)
10+
import Json.Form.Helper as Helper
11+
12+
13+
switch : Model -> Schema -> Bool -> Path -> Html Msg
14+
switch model schema isRequired path =
15+
let
16+
isChecked =
17+
case model.value |> Maybe.andThen (JsonValue.getIn path >> Result.toMaybe) of
18+
Just (BoolValue x) ->
19+
x
20+
21+
_ ->
22+
False
23+
24+
( hasError, helperText ) =
25+
Helper.view model schema path
26+
in
27+
label
28+
[ classList
29+
[ ( "jf-switch", True )
30+
, ( "jf-switch--on", isChecked )
31+
, ( "jf-switch--focused", model.focused |> Maybe.map ((==) path) |> Maybe.withDefault False )
32+
, ( "jf-switch--invalid", hasError )
33+
]
34+
]
35+
[ input
36+
[ type_ "checkbox"
37+
, class "jf-switch__input"
38+
, checked isChecked
39+
, onFocus <| FocusInput (Just path)
40+
, onBlur <| FocusInput Nothing
41+
, onCheck <| (JsonValue.BoolValue >> EditValue path)
42+
]
43+
[]
44+
, span [ class "jf-switch__label" ] [ schema |> getTitle isRequired |> text ]
45+
, div [ class "jf-switch__track" ] []
46+
, div [ class "jf-switch__thumb" ] []
47+
, div [ class "jf-switch__helper-text" ] [ helperText ]
48+
]
49+
50+
51+
checkbox : Model -> Schema -> Bool -> Path -> Html Msg
52+
checkbox model schema isRequired path =
53+
let
54+
isChecked =
55+
case model.value |> Maybe.andThen (JsonValue.getIn path >> Result.toMaybe) of
56+
Just (BoolValue x) ->
57+
x
58+
59+
_ ->
60+
False
61+
62+
( hasError, helperText ) =
63+
Helper.view model schema path
64+
in
65+
label
66+
[ classList
67+
[ ( "jf-checkbox", True )
68+
, ( "jf-checkbox--on", isChecked )
69+
, ( "jf-checkbox--focused", model.focused |> Maybe.map ((==) path) |> Maybe.withDefault False )
70+
, ( "jf-checkbox--invalid", hasError )
71+
]
72+
]
73+
[ input
74+
[ type_ "checkbox"
75+
, class "jf-checkbox__input"
76+
, checked isChecked
77+
, onFocus <| FocusInput (Just path)
78+
, onBlur <| FocusInput Nothing
79+
, onCheck <| (JsonValue.BoolValue >> EditValue path)
80+
]
81+
[]
82+
, span [ class "jf-checkbox__label" ] [ schema |> getTitle isRequired |> text ]
83+
, div [ class "jf-checkbox__box-outline" ]
84+
[ div [ class "jf-checkbox__tick-outline" ] []
85+
]
86+
, div [ class "jf-checkbox__helper-text" ] [ helperText ]
87+
]

0 commit comments

Comments
 (0)