Skip to content

Commit a95efeb

Browse files
committed
Merge tag 'v0.7.0' into kimi/borderless-list
v0.7.0
2 parents 7731f3b + 50caeaf commit a95efeb

File tree

9 files changed

+219
-196
lines changed

9 files changed

+219
-196
lines changed

docs/Examples/Form.example.purs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ data Action formData formResult
4747
| SetForceTopLabels Boolean
4848
| SetReadonly Boolean
4949
| SetSimulatePauses Boolean
50-
| SetUser (Maybe formResult) formData
50+
| SetUser (formData -> formData)
5151
| Submit
5252
| Reset
5353

@@ -79,11 +79,18 @@ docs = unit # make component { initialState, render }
7979
SetSimulatePauses simulatePauses ->
8080
self.setState _ { simulatePauses = simulatePauses }
8181

82-
SetUser result user ->
83-
self.setState _
84-
{ result = result
85-
, user = user
86-
}
82+
SetUser update ->
83+
let
84+
formProps =
85+
{ loadColor: loadColor self.state.simulatePauses
86+
, loadColors: loadColors self.state.simulatePauses
87+
, readonly: self.state.readonly
88+
}
89+
in
90+
self.setState \s -> s
91+
{ result = F.revalidate userForm formProps (update s.user)
92+
, user = update s.user
93+
}
8794

8895
Submit ->
8996
self.setState \state -> state { user = F.setModified state.user, modalOpen = isJust state.result }
@@ -155,7 +162,7 @@ docs = unit # make component { initialState, render }
155162
, children:
156163
[ userComponent
157164
{ value: user
158-
, onChange: \r -> send self <<< SetUser r
165+
, onChange: send self <<< SetUser
159166
, loadColor: loadColor simulatePauses
160167
, loadColors: loadColors simulatePauses
161168
, inlineTable
@@ -264,15 +271,27 @@ type ValidatedUser =
264271
-- | remounting this component on each render.
265272
userComponent
266273
:: { value :: User
267-
, onChange :: Maybe ValidatedUser -> User -> Effect Unit
274+
, onChange :: (User -> User) -> Effect Unit
268275
, loadColor :: String -> Aff { label :: String, value :: String }
269276
, loadColors :: String -> Aff (Array { label :: String, value :: String })
270277
, inlineTable :: Boolean
271278
, forceTopLabels :: Boolean
272279
, readonly :: Boolean
273280
}
274281
-> JSX
275-
userComponent = F.build ado
282+
userComponent = F.build userForm
283+
284+
userForm
285+
:: forall props
286+
. FormBuilder
287+
{ loadColor :: String -> Aff { label :: String, value :: String }
288+
, loadColors :: String -> Aff (Array { label :: String, value :: String })
289+
, readonly :: Boolean
290+
| props
291+
}
292+
User
293+
ValidatedUser
294+
userForm = ado
276295
firstName <-
277296
F.indent "First Name" Required
278297
$ F.focus (prop (SProxy :: SProxy "firstName"))

docs/Examples/Layouts.example.purs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ docs = (\c -> element c {}) $ withRouter $ toReactComponent identity component {
275275
, renderCell: \rowData -> R.text rowData.createdDate
276276
}
277277
]
278+
, onColumnChange: toNullable Nothing
278279
}
279280

280281
overviewTableData =

docs/Examples/Table.example.purs

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,32 @@ docs = unit # make component { initialState, render }
3535
{ sort: SortString "asc"
3636
, sortBy: Just (ColumnName "createdDate")
3737
, selected: ["10cms9", "0mf7w"]
38+
, ex2Columns:
39+
[ { required: true
40+
, name: ColumnName "product-type"
41+
, label: notNull "Product type"
42+
, filterLabel: null
43+
, sortBy: notNull $ ColumnName "title"
44+
, style: css {}
45+
, hidden: false
46+
, sticky: false
47+
, renderCell: \rowData ->
48+
Link.link Link.defaults
49+
{ href = rowData.link
50+
, text = R.text rowData.title
51+
}
52+
}
53+
, { required: true
54+
, name: ColumnName "created-date"
55+
, label: notNull "Created date"
56+
, filterLabel: null
57+
, sortBy: notNull $ ColumnName "createdDate"
58+
, style: css {}
59+
, hidden: false
60+
, sticky: false
61+
, renderCell: \rowData -> R.text rowData.createdDate
62+
}
63+
]
3864
}
3965

4066
render self =
@@ -109,6 +135,7 @@ docs = unit # make component { initialState, render }
109135
, renderCell: \rowData -> R.text rowData.createdDate
110136
}
111137
]
138+
, onColumnChange: null
112139
}
113140
]
114141
}
@@ -149,32 +176,9 @@ docs = unit # make component { initialState, render }
149176
, renderCell: R.text <<< _.title
150177
, sticky: false
151178
}
152-
, columns:
153-
[ { required: true
154-
, name: ColumnName "product-type"
155-
, label: notNull "Product type"
156-
, filterLabel: null
157-
, sortBy: notNull $ ColumnName "title"
158-
, style: css {}
159-
, hidden: false
160-
, sticky: false
161-
, renderCell: \rowData ->
162-
Link.link Link.defaults
163-
{ href = rowData.link
164-
, text = R.text rowData.title
165-
}
166-
}
167-
, { required: true
168-
, name: ColumnName "created-date"
169-
, label: notNull "Created date"
170-
, filterLabel: null
171-
, sortBy: notNull $ ColumnName "createdDate"
172-
, style: css {}
173-
, hidden: false
174-
, sticky: false
175-
, renderCell: \rowData -> R.text rowData.createdDate
176-
}
177-
]
179+
, columns: self.state.ex2Columns
180+
, onColumnChange: notNull $ mkEffectFn1 \columns ->
181+
self.setState _ { ex2Columns = columns }
178182
}
179183
]
180184
}

src/Lumi/Components/Form.purs

Lines changed: 29 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
module Lumi.Components.Form
2-
( module Internal
2+
( module Defaults
3+
, module Internal
34
, module Validation
45
, build
5-
, buildConcurrently
6-
, buildWithDefaults
76
, static
87
, section
98
, inputBox
@@ -66,7 +65,8 @@ import JSS (JSS, jss)
6665
import Lumi.Components.Color (colors)
6766
import Lumi.Components.Column (column)
6867
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)
7070
import Lumi.Components.Form.Internal (FormBuilder, SeqFormBuilder, formBuilder, formBuilder_, invalidate, listen, parallel, revalidate, sequential) as Internal
7171
import Lumi.Components.Form.Validation (Validated(..), Validator, _Validated, fromValidated, mustBe, mustEqual, nonEmpty, nonEmptyArray, nonNull, validNumber, validInt, optional, setFresh, setModified, validated, warn) as Validation
7272
import Lumi.Components.Input (alignToInput)
@@ -89,7 +89,7 @@ import React.Basic.DOM (css, unsafeCreateDOMComponent)
8989
import React.Basic.DOM as R
9090
import React.Basic.DOM.Events (capture, stopPropagation, targetChecked, targetValue)
9191
import React.Basic.Events as Events
92-
import Record (disjointUnion, get)
92+
import Record (get)
9393
import Type.Row (class Cons)
9494
import Unsafe.Coerce (unsafeCoerce)
9595

@@ -98,30 +98,6 @@ import Unsafe.Coerce (unsafeCoerce)
9898
-- | _Note_: this function should be fully applied, to avoid remounting
9999
-- | the component on each render.
100100
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
125101
:: forall props unvalidated result
126102
. FormBuilder { readonly :: Boolean | props } unvalidated result
127103
-> { value :: unvalidated
@@ -132,7 +108,7 @@ buildConcurrently
132108
| props
133109
}
134110
-> JSX
135-
buildConcurrently editor = makeStateless (createComponent "Form") render where
111+
build editor = makeStateless (createComponent "Form") render where
136112
render props@{ value, onChange, inlineTable, forceTopLabels, readonly } =
137113

138114
let forest = Array.mapMaybe pruneTree $ edit onChange
@@ -159,8 +135,10 @@ buildConcurrently editor = makeStateless (createComponent "Form") render where
159135
Child { key, child } ->
160136
maybe identity keyed key $ child
161137
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+
}
164142
Node { label, key, required, validationError, children } ->
165143
maybe identity keyed key $ labeledField
166144
{ label: text body
@@ -182,29 +160,6 @@ buildConcurrently editor = makeStateless (createComponent "Form") render where
182160
, children: surround fieldDivider (map toRow forest)
183161
}
184162

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-
208163
-- | Create an always-valid `FormBuilder` that renders the supplied `JSX`.
209164
static :: forall props value. JSX -> FormBuilder props value Unit
210165
static edit = formBuilder \_ _ -> { edit: const edit, validate: pure unit }
@@ -786,17 +741,20 @@ fetch_ loading getData = fetch loading "" (const getData)
786741
-- | A dummy form that, whenever the specified key changes, performs an
787742
-- | asynchronous effect. It displays the specified JSX while the effect is not
788743
-- | 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
790745
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+
}
796754

797755
-- | A dummy form that, whenever the specified key changes, performs an
798756
-- | 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
800758
effect key = asyncEffect key mempty <<< liftEffect
801759

802760
-- | Sequential `SeqFormBuilder` used for asynchronously initializing some
@@ -823,16 +781,18 @@ initializer
823781
:: forall props value
824782
. Nub (initialized :: Boolean | value) (initialized :: Boolean | value)
825783
=> JSX
826-
-> (props -> {| value } -> Aff {| value })
784+
-> (props -> {| value } -> Aff ({ initialized :: Boolean | value } -> { initialized :: Boolean | value }))
827785
-> SeqFormBuilder props { initialized :: Boolean | value } Unit
828786
initializer loader aff =
829787
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)
836796
where
837797
contractValue :: { initialized :: Boolean | value } -> {| value }
838798
contractValue = unsafeCoerce

src/Lumi/Components/Form/Defaults.purs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Prelude
1010
import Data.Either (Either(..))
1111
import Data.Maybe (Maybe(..))
1212
import Data.Symbol (class IsSymbol, SProxy(..))
13-
import Lumi.Components.Form (Validated(..))
13+
import Lumi.Components.Form.Validation (Validated(..))
1414
import Prim.Row (class Cons, class Lacks)
1515
import Prim.RowList (class RowToList, Cons, Nil)
1616
import Record.Builder (Builder)

src/Lumi/Components/Loader.purs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ styles = jss
4040
spinnerMixin :: { radius :: String, borderWidth :: String } -> JSS
4141
spinnerMixin { radius, borderWidth } = jss
4242
{ boxSizing: "border-box"
43-
, content: ""
43+
, content: "\"\""
4444
, display: "inline-block"
4545
, height: radius
4646
, width: radius

src/Lumi/Components/Table.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ exports.checkIsEventTargetInTree = function(domNode, e) {
1919
return e.target === domNode || domNode.contains(e.target);
2020
};
2121

22+
exports.isRightClick = function(e) {
23+
return e.button === 2;
24+
};
25+
2226
exports.hasWindowSelection = function() {
2327
return window.getSelection().type === "Range";
2428
};

0 commit comments

Comments
 (0)