@@ -9,17 +9,17 @@ import Data.Foldable (foldMap)
99import Data.Int as Int
1010import Data.Lens (iso )
1111import Data.Lens.Record (prop )
12- import Data.Maybe (Maybe (..), fromMaybe , isJust , maybe )
12+ import Data.Maybe (Maybe (..), isJust , maybe )
1313import Data.Monoid as Monoid
1414import Data.Newtype (class Newtype , un )
1515import Data.Nullable as Nullable
1616import Data.String as String
1717import Data.String.NonEmpty (NonEmptyString , appendString , length , toString )
1818import Data.Symbol (SProxy (..))
19- import Effect (Effect )
2019import Effect.Aff (Milliseconds (..), delay , error , throwError )
2120import Effect.Class (liftEffect )
2221import Effect.Random (randomRange )
22+ import Effect.Unsafe (unsafePerformEffect )
2323import Lumi.Components.Button as Button
2424import Lumi.Components.Column (column , column_ )
2525import Lumi.Components.Example (example )
@@ -28,179 +28,135 @@ import Lumi.Components.Form as F
2828import Lumi.Components.Form.Defaults (formDefaults )
2929import Lumi.Components.Form.Table as FT
3030import Lumi.Components.Input as Input
31- import Lumi.Components.LabeledField (labeledField , RequiredField (..))
31+ import Lumi.Components.LabeledField (RequiredField (..))
3232import Lumi.Components.Modal (dialog )
3333import Lumi.Components.Row (row )
3434import Lumi.Components.Size (Size (..))
35- import Lumi.Components.Text (h1_ )
3635import Lumi.Components.Upload (FileId (..))
3736import Lumi.Components.Upload as Upload
38- import React.Basic (Component , JSX , createComponent , make )
3937import React.Basic.DOM (css )
4038import React.Basic.DOM as R
41- import React.Basic.DOM.Events (targetChecked )
39+ import React.Basic.DOM.Events (preventDefault )
4240import React.Basic.Events (handler , handler_ )
41+ import React.Basic.Hooks (JSX , CreateComponent , component , element , useEffect , useState , (/\))
42+ import React.Basic.Hooks as React
4343import Web.File.File as File
4444
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-
5745docs :: 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
7147
72- send self = case _ of
73- SetInlineTable inlineTable ->
74- self.setState _ { inlineTable = inlineTable }
48+ userFormExample <- mkUserFormExample
7549
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+ }
9657
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+ }
9963
100- Reset ->
101- self.setState (const initialState)
64+ , example $ element userFormExample formData
65+ ]
10266
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+ }
106117
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" }
109133 , 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
133137 }
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" }
157142 }
158143 ]
159144 }
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
191146 Nothing ->
192147 mempty
193148 Just { firstName, lastName } ->
194149 dialog
195150 { modalOpen
196- , onRequestClose: send self Reset
151+ , onRequestClose: reset
197152 , onActionButtonClick: Nullable .null
198153 , actionButtonTitle: " "
199154 , size: Medium
200155 , children: R .text $
201156 " Created user " <> toString firstName <> " " <> toString lastName <> " !"
202157 }
203158 ]
159+ }
204160
205161data Country
206162 = BR
@@ -266,19 +222,6 @@ type ValidatedPet =
266222 , color :: Maybe String
267223 }
268224
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-
282225userForm
283226 :: forall props
284227 . FormBuilder
@@ -499,7 +442,6 @@ userForm = ado
499442 , { label: " Blue" , value: " blue" }
500443 ]
501444
502-
503445type Address =
504446 { name :: Validated String
505447 , street :: Validated String
0 commit comments