@@ -9,17 +9,17 @@ import Data.Foldable (foldMap)
9
9
import Data.Int as Int
10
10
import Data.Lens (iso )
11
11
import Data.Lens.Record (prop )
12
- import Data.Maybe (Maybe (..), fromMaybe , isJust , maybe )
12
+ import Data.Maybe (Maybe (..), isJust , maybe )
13
13
import Data.Monoid as Monoid
14
14
import Data.Newtype (class Newtype , un )
15
15
import Data.Nullable as Nullable
16
16
import Data.String as String
17
17
import Data.String.NonEmpty (NonEmptyString , appendString , length , toString )
18
18
import Data.Symbol (SProxy (..))
19
- import Effect (Effect )
20
19
import Effect.Aff (Milliseconds (..), delay , error , throwError )
21
20
import Effect.Class (liftEffect )
22
21
import Effect.Random (randomRange )
22
+ import Effect.Unsafe (unsafePerformEffect )
23
23
import Lumi.Components.Button as Button
24
24
import Lumi.Components.Column (column , column_ )
25
25
import Lumi.Components.Example (example )
@@ -28,179 +28,135 @@ import Lumi.Components.Form as F
28
28
import Lumi.Components.Form.Defaults (formDefaults )
29
29
import Lumi.Components.Form.Table as FT
30
30
import Lumi.Components.Input as Input
31
- import Lumi.Components.LabeledField (labeledField , RequiredField (..))
31
+ import Lumi.Components.LabeledField (RequiredField (..))
32
32
import Lumi.Components.Modal (dialog )
33
33
import Lumi.Components.Row (row )
34
34
import Lumi.Components.Size (Size (..))
35
- import Lumi.Components.Text (h1_ )
36
35
import Lumi.Components.Upload (FileId (..))
37
36
import Lumi.Components.Upload as Upload
38
- import React.Basic (Component , JSX , createComponent , make )
39
37
import React.Basic.DOM (css )
40
38
import React.Basic.DOM as R
41
- import React.Basic.DOM.Events (targetChecked )
39
+ import React.Basic.DOM.Events (preventDefault )
42
40
import React.Basic.Events (handler , handler_ )
41
+ import React.Basic.Hooks (JSX , CreateComponent , component , element , useEffect , useState , (/\))
42
+ import React.Basic.Hooks as React
43
43
import Web.File.File as File
44
44
45
- component :: Component Unit
46
- component = createComponent " FormExample"
47
-
48
- data Action formData formResult
49
- = SetInlineTable Boolean
50
- | SetForceTopLabels Boolean
51
- | SetReadonly Boolean
52
- | SetSimulatePauses Boolean
53
- | SetUser (formData -> formData )
54
- | Submit
55
- | Reset
56
-
57
45
docs :: JSX
58
- docs = unit # make component { initialState, render }
59
- where
60
- initialState =
61
- { user: (formDefaults :: User )
62
- { leastFavoriteColors = [" red" ]
63
- }
64
- , result: Nothing :: Maybe ValidatedUser
65
- , modalOpen: false
66
- , inlineTable: false
67
- , forceTopLabels: false
68
- , readonly: false
69
- , simulatePauses: true
70
- }
46
+ docs = flip element {} $ unsafePerformEffect do
71
47
72
- send self = case _ of
73
- SetInlineTable inlineTable ->
74
- self.setState _ { inlineTable = inlineTable }
48
+ userFormExample <- mkUserFormExample
75
49
76
- SetForceTopLabels forceTopLabels ->
77
- self.setState _ { forceTopLabels = forceTopLabels }
78
-
79
- SetReadonly readonly ->
80
- self.setState _ { readonly = readonly }
81
-
82
- SetSimulatePauses simulatePauses ->
83
- self.setState _ { simulatePauses = simulatePauses }
84
-
85
- SetUser update ->
86
- let
87
- formProps =
88
- { readonly: self.state.readonly
89
- , simulatePauses: self.state.simulatePauses
90
- }
91
- in
92
- self.setState \s -> s
93
- { result = F .revalidate userForm formProps (update s.user)
94
- , user = update s.user
95
- }
50
+ component " FormExample" \_ -> React .do
51
+ { formData, form } <- F .useForm metaForm
52
+ { initialState: formDefaults
53
+ , readonly: false
54
+ , inlineTable: false
55
+ , forceTopLabels: false
56
+ }
96
57
97
- Submit ->
98
- self.setState \state -> state { user = F .setModified state.user, modalOpen = isJust state.result }
58
+ pure $ column_
59
+ [ column
60
+ { style: css { width: " 100%" , maxWidth: 300 , padding: " 2rem 0" }
61
+ , children: [ form ]
62
+ }
99
63
100
- Reset ->
101
- self.setState (const initialState)
64
+ , example $ element userFormExample formData
65
+ ]
102
66
103
- render self@{ state: { user, result, inlineTable, forceTopLabels, readonly, simulatePauses, modalOpen } } =
104
- column_
105
- [ h1_ " Form"
67
+ -- | This form renders the toggles at the top of the example
68
+ metaForm
69
+ :: forall props
70
+ . FormBuilder
71
+ { readonly :: Boolean
72
+ | props
73
+ }
74
+ { inlineTable :: Boolean
75
+ , forceTopLabels :: Boolean
76
+ , readonly :: Boolean
77
+ , simulatePauses :: Boolean
78
+ }
79
+ Unit
80
+ metaForm = ado
81
+ inlineTable <-
82
+ F .indent " Inline table" Neither
83
+ $ F .focus (prop (SProxy :: SProxy " inlineTable" ))
84
+ $ F .switch
85
+ forceTopLabels <-
86
+ F .indent " Force top labels" Neither
87
+ $ F .focus (prop (SProxy :: SProxy " forceTopLabels" ))
88
+ $ F .switch
89
+ readonly <-
90
+ F .indent " Readonly" Neither
91
+ $ F .focus (prop (SProxy :: SProxy " readonly" ))
92
+ $ F .switch
93
+ simulatePauses <-
94
+ F .indent " Simulate pauses (pet color picker)" Neither
95
+ $ F .focus (prop (SProxy :: SProxy " simulatePauses" ))
96
+ $ F .switch
97
+ in unit
98
+
99
+ mkUserFormExample
100
+ :: CreateComponent
101
+ { inlineTable :: Boolean
102
+ , forceTopLabels :: Boolean
103
+ , readonly :: Boolean
104
+ , simulatePauses :: Boolean
105
+ }
106
+ mkUserFormExample = do
107
+ component " UserFormExample" \props -> React .do
108
+ modalOpen /\ setModalOpen <- useState false
109
+
110
+ { setModified, reset, validated, form } <- F .useForm userForm
111
+ { initialState: formDefaults
112
+ , readonly: props.readonly
113
+ , inlineTable: props.inlineTable
114
+ , forceTopLabels: props.forceTopLabels && not props.inlineTable
115
+ , simulatePauses: props.simulatePauses
116
+ }
106
117
107
- , column
108
- { style: css { maxWidth: " 50rem" , padding: " 2rem 0" }
118
+ let hasResult = isJust validated
119
+ useEffect hasResult do
120
+ setModalOpen $ const hasResult
121
+ mempty
122
+
123
+ pure $ R .form -- Forms should be enclosed in a single "<form>" element to enable
124
+ -- default browser behavior, such as the enter key. Use "type=submit"
125
+ -- on the form's submit button and `preventDefault` to keep the browser
126
+ -- from reloading the page on submission.
127
+ { onSubmit: handler preventDefault \_ -> setModified
128
+ , style: R .css { alignSelf: " stretch" }
129
+ , children:
130
+ [ form
131
+ , row
132
+ { style: R .css { justifyContent: " flex-end" }
109
133
, children:
110
- [ labeledField
111
- { label: R .text " Inline Table"
112
- , value: Input .input Input .switch
113
- { checked = if inlineTable then Input.On else Input.Off
114
- , onChange = handler targetChecked $ send self <<< SetInlineTable <<< fromMaybe false
115
- }
116
- , validationError: Nothing
117
- , required: Neither
118
- , forceTopLabel: false
119
- , style: css {}
120
- }
121
-
122
- , labeledField
123
- { label: R .text " Force Top Labels"
124
- , value: Input .input Input .switch
125
- { checked = if forceTopLabels then Input.On else Input.Off
126
- , disabled = inlineTable
127
- , onChange = handler targetChecked $ send self <<< SetForceTopLabels <<< fromMaybe false
128
- }
129
- , validationError: Nothing
130
- , required: Neither
131
- , forceTopLabel: false
132
- , style: css {}
134
+ [ Button .button Button .secondary
135
+ { title = " Reset"
136
+ , onPress = handler_ reset
133
137
}
134
-
135
- , labeledField
136
- { label: R .text " Readonly"
137
- , value: Input .input Input .switch
138
- { checked = if readonly then Input.On else Input.Off
139
- , onChange = handler targetChecked $ send self <<< SetReadonly <<< fromMaybe false
140
- }
141
- , validationError: Nothing
142
- , required: Neither
143
- , forceTopLabel: false
144
- , style: css {}
145
- }
146
-
147
- , labeledField
148
- { label: R .text " Simulate pauses"
149
- , value: Input .input Input .switch
150
- { checked = if simulatePauses then Input.On else Input.Off
151
- , onChange = handler targetChecked $ send self <<< SetSimulatePauses <<< fromMaybe false
152
- }
153
- , validationError: Nothing
154
- , required: Neither
155
- , forceTopLabel: false
156
- , style: css {}
138
+ , Button .button Button .primary
139
+ { title = " Submit"
140
+ , type = " submit"
141
+ , style = R .css { marginLeft: " 12px" }
157
142
}
158
143
]
159
144
}
160
-
161
- , example
162
- $ column
163
- { style: css { alignSelf: " stretch" }
164
- , children:
165
- [ userComponent
166
- { value: user
167
- , onChange: send self <<< SetUser
168
- , inlineTable
169
- , forceTopLabels: forceTopLabels && not inlineTable
170
- , readonly
171
- , simulatePauses
172
- }
173
- , row
174
- { style: css { justifyContent: " flex-end" }
175
- , children:
176
- [ Button .button Button .secondary
177
- { title = " Reset"
178
- , onPress = handler_ $ send self Reset
179
- }
180
- , Button .button Button .primary
181
- { title = " Submit"
182
- , style = css { marginLeft: " 12px" }
183
- , onPress = handler_ $ send self Submit
184
- }
185
- ]
186
- }
187
- ]
188
- }
189
-
190
- , case result of
145
+ , case validated of
191
146
Nothing ->
192
147
mempty
193
148
Just { firstName, lastName } ->
194
149
dialog
195
150
{ modalOpen
196
- , onRequestClose: send self Reset
151
+ , onRequestClose: reset
197
152
, onActionButtonClick: Nullable .null
198
153
, actionButtonTitle: " "
199
154
, size: Medium
200
155
, children: R .text $
201
156
" Created user " <> toString firstName <> " " <> toString lastName <> " !"
202
157
}
203
158
]
159
+ }
204
160
205
161
data Country
206
162
= BR
@@ -266,19 +222,6 @@ type ValidatedPet =
266
222
, color :: Maybe String
267
223
}
268
224
269
- -- | We have to fully apply `Form.build` in order to avoid
270
- -- | remounting this component on each render.
271
- userComponent
272
- :: { value :: User
273
- , onChange :: (User -> User ) -> Effect Unit
274
- , inlineTable :: Boolean
275
- , forceTopLabels :: Boolean
276
- , readonly :: Boolean
277
- , simulatePauses :: Boolean
278
- }
279
- -> JSX
280
- userComponent = F .build userForm
281
-
282
225
userForm
283
226
:: forall props
284
227
. FormBuilder
@@ -499,7 +442,6 @@ userForm = ado
499
442
, { label: " Blue" , value: " blue" }
500
443
]
501
444
502
-
503
445
type Address =
504
446
{ name :: Validated String
505
447
, street :: Validated String
0 commit comments