Skip to content

Commit d5d9512

Browse files
authored
Form updates (#131)
* input checkbox * export checkbox * checkbox alignment * checkbox with description * inputPlaceholderText_ * textarea_ * cleanup + fix export * code review * WIP checkbox title/subtitle alignment * readonly * readonly code review * arthurxavierx: Align label in checkbox form builder * cleanup
1 parent 8b7b2a4 commit d5d9512

File tree

3 files changed

+96
-2
lines changed

3 files changed

+96
-2
lines changed

docs/Examples/Form.example.purs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module Lumi.Components.Examples.Form where
22

33
import Prelude
44

5+
import Color (cssStringHSLA)
56
import Control.Coroutine.Aff (close, emit, produceAff)
67
import Control.MonadZero (guard)
78
import Data.Array as Array
@@ -22,6 +23,7 @@ import Effect.Class (liftEffect)
2223
import Effect.Random (randomRange)
2324
import Effect.Unsafe (unsafePerformEffect)
2425
import Lumi.Components.Button as Button
26+
import Lumi.Components.Color (colors)
2527
import Lumi.Components.Column (column, column_)
2628
import Lumi.Components.Example (example)
2729
import Lumi.Components.Form (FormBuilder, Validated)
@@ -33,6 +35,8 @@ import Lumi.Components.LabeledField (RequiredField(..))
3335
import Lumi.Components.Modal (dialog)
3436
import Lumi.Components.Row (row)
3537
import Lumi.Components.Size (Size(..))
38+
import Lumi.Components.Text as T
39+
import Lumi.Components.Textarea as Textarea
3640
import Lumi.Components.Upload (FileId(..))
3741
import Lumi.Components.Upload as Upload
3842
import React.Basic.DOM (css)
@@ -193,6 +197,8 @@ type User =
193197
, password2 :: Validated String
194198
}
195199
, admin :: Boolean
200+
, checkbox :: Boolean
201+
, descriptiveCheckbox :: Boolean
196202
, height :: Validated String
197203
, addresses :: Validated (Array Address)
198204
, pets :: Validated (Array Pet)
@@ -206,6 +212,8 @@ type ValidatedUser =
206212
, lastName :: NonEmptyString
207213
, password :: NonEmptyString
208214
, admin :: Boolean
215+
, checkbox :: Boolean
216+
, descriptiveCheckbox :: Boolean
209217
, height :: Maybe Number
210218
, addresses :: Array ValidatedAddress
211219
, pets :: Array ValidatedPet
@@ -248,7 +256,7 @@ userForm = ado
248256
(pure "First name should be longer than two characters (but it doesn't have to be).")
249257
)
250258
$ F.validated (F.nonEmpty "First name")
251-
$ F.textbox
259+
$ F.inputBox $ Input.text_ { placeholder = "First name" }
252260
lastName <-
253261
F.indent "Last Name" Required
254262
$ F.focus (prop (SProxy :: SProxy "lastName"))
@@ -272,6 +280,23 @@ userForm = ado
272280
F.indent "Admin?" Neither
273281
$ F.focus (prop (SProxy :: SProxy "admin"))
274282
$ F.switch
283+
checkbox <-
284+
F.indent "Checked?" Neither
285+
$ F.focus (prop (SProxy :: SProxy "checkbox"))
286+
$ F.checkbox
287+
descriptiveCheckbox <-
288+
F.focus (prop (SProxy :: SProxy "descriptiveCheckbox"))
289+
$ F.labeledCheckbox
290+
$ column
291+
{ style: R.css { maxWidth: "300px" }
292+
, children:
293+
[ T.body_ "This is a right aligned description"
294+
, T.text T.subtext
295+
{ style = R.css { color: cssStringHSLA colors.black1 }
296+
, children = [ R.text "with a sublabel that reads \"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\"" ]
297+
}
298+
]
299+
}
275300

276301
F.section "Personal data"
277302
height <-
@@ -306,6 +331,10 @@ userForm = ado
306331
F.indent "Notes" Optional
307332
$ F.focus (prop (SProxy :: SProxy "notes"))
308333
$ F.textarea
334+
notes <-
335+
F.indent "Notes (with placeholder)" Optional
336+
$ F.focus (prop (SProxy :: SProxy "notes"))
337+
$ F.textarea_ $ Textarea.defaults { placeholder = "Placeholder text..." }
309338

310339
F.section "Pets"
311340
pets <-
@@ -418,6 +447,8 @@ userForm = ado
418447
, lastName
419448
, password
420449
, admin
450+
, checkbox
451+
, descriptiveCheckbox
421452
, height
422453
, pets
423454
, leastFavoriteColors
@@ -523,4 +554,3 @@ addressForm = ado
523554
{ label: un State state
524555
, value: state
525556
}
526-

src/Lumi/Components/Form.purs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ module Lumi.Components.Form
1414
, textbox
1515
, passwordBox
1616
, textarea
17+
, textarea_
1718
, switch
19+
, checkbox
20+
, labeledCheckbox
1821
, radioGroup
1922
, file
2023
, genericSelect
@@ -352,6 +355,23 @@ passwordBox
352355
String
353356
passwordBox = inputBox Input.password
354357

358+
-- | A configurable textarea box makes a `FormBuilder` for strings
359+
textarea_
360+
:: forall props
361+
. Textarea.TextareaProps
362+
-> FormBuilder
363+
{ readonly :: Boolean | props }
364+
String
365+
String
366+
textarea_ textareaProps = formBuilder_ \{ readonly } s onChange ->
367+
if readonly
368+
then Input.alignToInput $ R.text s
369+
else Textarea.textarea textareaProps
370+
{ value = s
371+
, onChange = capture targetValue (traverse_ onChange)
372+
, style = R.css { width: "100%" }
373+
}
374+
355375
-- | A simple text box makes a `FormBuilder` for strings
356376
textarea
357377
:: forall props
@@ -383,6 +403,44 @@ switch = formBuilder_ \{ readonly } b onChange ->
383403
, onChange = Events.handler (stopPropagation >>> targetChecked) (traverse_ onChange)
384404
}
385405

406+
-- | A `checkbox` is an editor for booleans which displays checked or not checked.
407+
checkbox :: forall props. FormBuilder { readonly :: Boolean | props } Boolean Boolean
408+
checkbox = labeledCheckbox mempty
409+
410+
-- | A `labeledCheckbox` is an editor that behaves exactly like `checkbox` but
411+
-- | also accepts a JSX displayed as a label to its right.
412+
labeledCheckbox
413+
:: forall props
414+
. JSX
415+
-> FormBuilder { readonly :: Boolean | props } Boolean Boolean
416+
labeledCheckbox label =
417+
formBuilder_ \{ readonly } value onChange ->
418+
Input.label
419+
{ style: R.css
420+
{ flexDirection: "row"
421+
, alignSelf: "stretch"
422+
, alignItems: "baseline"
423+
}
424+
, for: null
425+
, children:
426+
[ Input.input Input.checkbox
427+
{ style = R.css { marginBottom: "0", alignSelf: "baseline" }
428+
, checked = if value then Input.On else Input.Off
429+
, disabled = if readonly then true else false
430+
, onChange =
431+
if readonly
432+
then Events.handler Events.syntheticEvent \_ -> pure unit
433+
else Events.handler (stopPropagation >>> targetChecked) (traverse_ onChange)
434+
}
435+
, lumiAlignToInput
436+
{ style: { flex: "1", marginLeft: "8px" }
437+
, children: label
438+
}
439+
]
440+
}
441+
where
442+
lumiAlignToInput = element (R.unsafeCreateDOMComponent "lumi-align-to-input")
443+
386444
-- | A form that edits an optional structure represented by group of radio
387445
-- | buttons, visually oriented in either horizontal or vertical fashion.
388446
-- |

src/Lumi/Components/Input.purs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,14 +372,20 @@ styles = jss
372372
, lineHeight: "1"
373373
}
374374
}
375+
, "&::before":
376+
{ content: "'•'"
377+
, visibility: "hidden"
378+
}
375379
, "&:checked":
376380
{ "&::before":
377381
{ content: "'✓'"
382+
, visibility: "visible"
378383
}
379384
}
380385
, "&:indeterminate":
381386
{ "&::before":
382387
{ content: "'⎻'"
388+
, visibility: "visible"
383389
}
384390
}
385391
, "&:disabled":

0 commit comments

Comments
 (0)