1
1
module Lumi.Components.Form
2
- ( module Internal
2
+ ( module Defaults
3
+ , module Internal
3
4
, module Validation
4
5
, build
5
- , buildConcurrently
6
- , buildWithDefaults
7
6
, static
8
7
, section
9
8
, inputBox
@@ -66,7 +65,8 @@ import JSS (JSS, jss)
66
65
import Lumi.Components.Color (colors )
67
66
import Lumi.Components.Column (column )
68
67
import Lumi.Components.FetchCache as FetchCache
69
- import Lumi.Components.Form.Internal (FormBuilder (..), SeqFormBuilder , Tree (..), formBuilder , formBuilder_ , invalidate , revalidate , sequential , pruneTree )
68
+ import Lumi.Components.Form.Defaults (formDefaults ) as Defaults
69
+ import Lumi.Components.Form.Internal (FormBuilder (..), SeqFormBuilder , Tree (..), formBuilder , formBuilder_ , invalidate , pruneTree , sequential )
70
70
import Lumi.Components.Form.Internal (FormBuilder , SeqFormBuilder , formBuilder , formBuilder_ , invalidate , listen , parallel , revalidate , sequential ) as Internal
71
71
import Lumi.Components.Form.Validation (Validated (..), Validator , _Validated , fromValidated , mustBe , mustEqual , nonEmpty , nonEmptyArray , nonNull , validNumber , validInt , optional , setFresh , setModified , validated , warn ) as Validation
72
72
import Lumi.Components.Input (alignToInput )
@@ -89,7 +89,7 @@ import React.Basic.DOM (css, unsafeCreateDOMComponent)
89
89
import React.Basic.DOM as R
90
90
import React.Basic.DOM.Events (capture , stopPropagation , targetChecked , targetValue )
91
91
import React.Basic.Events as Events
92
- import Record (disjointUnion , get )
92
+ import Record (get )
93
93
import Type.Row (class Cons )
94
94
import Unsafe.Coerce (unsafeCoerce )
95
95
@@ -98,30 +98,6 @@ import Unsafe.Coerce (unsafeCoerce)
98
98
-- | _Note_: this function should be fully applied, to avoid remounting
99
99
-- | the component on each render.
100
100
build
101
- :: forall props unvalidated result
102
- . FormBuilder { readonly :: Boolean | props } unvalidated result
103
- -> { value :: unvalidated
104
- , onChange :: Maybe result -> unvalidated -> Effect Unit
105
- , inlineTable :: Boolean
106
- , forceTopLabels :: Boolean
107
- , readonly :: Boolean
108
- | props
109
- }
110
- -> JSX
111
- build editor = \props ->
112
- form props
113
- { onChange = \f ->
114
- let v = f props.value
115
- in props.onChange (revalidate editor (unsafeCoerce props) v) v
116
- }
117
- where
118
- form = buildConcurrently editor
119
-
120
- -- | Create a React component for a form from a `FormBuilder`.
121
- -- |
122
- -- | _Note_: this function should be fully applied, to avoid remounting
123
- -- | the component on each render.
124
- buildConcurrently
125
101
:: forall props unvalidated result
126
102
. FormBuilder { readonly :: Boolean | props } unvalidated result
127
103
-> { value :: unvalidated
@@ -132,7 +108,7 @@ buildConcurrently
132
108
| props
133
109
}
134
110
-> JSX
135
- buildConcurrently editor = makeStateless (createComponent " Form" ) render where
111
+ build editor = makeStateless (createComponent " Form" ) render where
136
112
render props@{ value, onChange, inlineTable, forceTopLabels, readonly } =
137
113
138
114
let forest = Array .mapMaybe pruneTree $ edit onChange
@@ -159,8 +135,10 @@ buildConcurrently editor = makeStateless (createComponent "Form") render where
159
135
Child { key, child } ->
160
136
maybe identity keyed key $ child
161
137
Wrapper { key, children } ->
162
- maybe identity keyed key $
163
- fragment [ intercalate fieldDivider (map toRow children) ]
138
+ R .div
139
+ { key: fromMaybe " " key
140
+ , children: [ intercalate fieldDivider (map toRow children) ]
141
+ }
164
142
Node { label, key, required, validationError, children } ->
165
143
maybe identity keyed key $ labeledField
166
144
{ label: text body
@@ -182,29 +160,6 @@ buildConcurrently editor = makeStateless (createComponent "Form") render where
182
160
, children: surround fieldDivider (map toRow forest)
183
161
}
184
162
185
- -- | Utility function.
186
- -- | Create a React component for a form from a `FormBuilder` and a default
187
- -- | form state. This default value is used in the form whenever the `value`
188
- -- | prop is `Nothing`.
189
- -- |
190
- -- | _Note_: this function should be fully applied, to avoid remounting
191
- -- | the component on each render.
192
- buildWithDefaults
193
- :: forall props unvalidated result
194
- . unvalidated
195
- -> FormBuilder { readonly :: Boolean | props } unvalidated result
196
- -> { value :: Maybe unvalidated
197
- , onChange :: Maybe result -> unvalidated -> Effect Unit
198
- , inlineTable :: Boolean
199
- , forceTopLabels :: Boolean
200
- , readonly :: Boolean
201
- | props
202
- }
203
- -> JSX
204
- buildWithDefaults defaults editor = \props -> form props { value = fromMaybe defaults props.value }
205
- where
206
- form = build editor
207
-
208
163
-- | Create an always-valid `FormBuilder` that renders the supplied `JSX`.
209
164
static :: forall props value . JSX -> FormBuilder props value Unit
210
165
static edit = formBuilder \_ _ -> { edit: const edit, validate: pure unit }
@@ -786,17 +741,20 @@ fetch_ loading getData = fetch loading "" (const getData)
786
741
-- | A dummy form that, whenever the specified key changes, performs an
787
742
-- | asynchronous effect. It displays the specified JSX while the effect is not
788
743
-- | complete, sets the form data to the result of the effect and returns it.
789
- asyncEffect :: forall props a . String -> JSX -> Aff a -> FormBuilder props a a
744
+ asyncEffect :: forall props a . String -> JSX -> Aff ( a -> a ) -> FormBuilder props a a
790
745
asyncEffect key loader aff =
791
- withKey key $ formBuilder_ \_ _ onChange ->
792
- keyed key $ asyncWithLoader loader do
793
- newValue <- aff
794
- liftEffect $ onChange newValue
795
- mempty
746
+ withKey key $ formBuilder \_ value ->
747
+ { edit: \onChange ->
748
+ keyed key $ asyncWithLoader loader do
749
+ f <- aff
750
+ liftEffect $ onChange f
751
+ mempty
752
+ , validate: Just value
753
+ }
796
754
797
755
-- | A dummy form that, whenever the specified key changes, performs an
798
756
-- | effect. It sets the form data to the result of the effect and returns it.
799
- effect :: forall props a . String -> Effect a -> FormBuilder props a a
757
+ effect :: forall props a . String -> Effect ( a -> a ) -> FormBuilder props a a
800
758
effect key = asyncEffect key mempty <<< liftEffect
801
759
802
760
-- | Sequential `SeqFormBuilder` used for asynchronously initializing some
@@ -823,16 +781,18 @@ initializer
823
781
:: forall props value
824
782
. Nub (initialized :: Boolean | value ) (initialized :: Boolean | value )
825
783
=> JSX
826
- -> (props -> { | value } -> Aff { | value } )
784
+ -> (props -> { | value } -> Aff ( { initialized :: Boolean | value } -> { initialized :: Boolean | value } ) )
827
785
-> SeqFormBuilder props { initialized :: Boolean | value } Unit
828
786
initializer loader aff =
829
787
sequential " initializer" $ withValue \value@{ initialized } -> withProps \props ->
830
- if initialized
831
- then pure unit
832
- else
833
- invalidate $ void $ asyncEffect " " loader do
834
- newValue <- aff props (contractValue value)
835
- pure $ disjointUnion { initialized: true } newValue
788
+ if initialized then
789
+ pure unit
790
+ else
791
+ invalidate
792
+ $ void
793
+ $ asyncEffect " " loader
794
+ $ map (_{ initialized = true } <<< _)
795
+ $ aff props (contractValue value)
836
796
where
837
797
contractValue :: { initialized :: Boolean | value } -> { | value }
838
798
contractValue = unsafeCoerce
0 commit comments