Skip to content

Commit d440c19

Browse files
authored
Allow dropdown buttons to close themselves, fixes #63 (#119)
* Allow dropdown buttons to close themselves, fixes #63 Fixes #63 by using the approach described in the original issue: add a callback to the `content` prop which allows the parent component to tell the dropdown button when it should close. * Code review feedback
1 parent dde8014 commit d440c19

File tree

5 files changed

+47
-17
lines changed

5 files changed

+47
-17
lines changed

docs/Examples/DropdownButton.example.purs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Color (cssStringHSLA)
66
import Data.Maybe (Maybe(..))
77
import Data.Nullable (toNullable)
88
import Effect.Console (log)
9+
import Effect.Uncurried (mkEffectFn1)
910
import Lumi.Components.Button (button, defaults, secondary)
1011
import Lumi.Components.Color (colors)
1112
import Lumi.Components.Column (column, column_)
@@ -25,20 +26,23 @@ docs =
2526
, example $
2627
dropdownButton dropdownButtonDefaults
2728
{ label = "Dropdown Button"
28-
, content = R.div
29+
, content = \closeSelf -> R.div
2930
{ style: R.css { width: "328px", padding: "12px" }
3031
, children:
3132
[ button secondary
3233
{ title = "I can be any element"
3334
, style = R.css { width: "100%", marginBottom: "8px" }
35+
, onPress = mkEffectFn1 \_ -> closeSelf
3436
}
3537
, button secondary
3638
{ title = "I can be any element"
3739
, style = R.css { width: "100%", marginBottom: "8px" }
40+
, onPress = mkEffectFn1 \_ -> closeSelf
3841
}
3942
, button defaults
4043
{ title = "I can be any element"
4144
, style = R.css { width: "100%" }
45+
, onPress = mkEffectFn1 \_ -> closeSelf
4246
}
4347
]
4448
}
@@ -49,20 +53,23 @@ docs =
4953
dropdownButton dropdownButtonDefaults
5054
{ label = "Dropdown Button"
5155
, alignment = toNullable (Just "right")
52-
, content = R.div
56+
, content = \closeSelf -> R.div
5357
{ style: R.css { width: "328px", padding: "12px" }
5458
, children:
5559
[ button secondary
5660
{ title = "I can be any element"
5761
, style = R.css { width: "100%", marginBottom: "8px" }
62+
, onPress = mkEffectFn1 \_ -> closeSelf
5863
}
5964
, button secondary
6065
{ title = "I can be any element"
6166
, style = R.css { width: "100%", marginBottom: "8px" }
67+
, onPress = mkEffectFn1 \_ -> closeSelf
6268
}
6369
, button defaults
6470
{ title = "I can be any element"
6571
, style = R.css { width: "100%" }
72+
, onPress = mkEffectFn1 \_ -> closeSelf
6673
}
6774
]
6875
}
@@ -77,20 +84,23 @@ docs =
7784
{ children:
7885
[ dropdownButton dropdownButtonDefaults
7986
{ label = "Dropdown Button"
80-
, content = R.div
87+
, content = \closeSelf -> R.div
8188
{ style: R.css { width: "328px", padding: "12px" }
8289
, children:
8390
[ button secondary
8491
{ title = "I can be any element"
8592
, style = R.css { width: "100%", marginBottom: "8px" }
93+
, onPress = mkEffectFn1 \_ -> closeSelf
8694
}
8795
, button secondary
8896
{ title = "I can be any element"
8997
, style = R.css { width: "100%", marginBottom: "8px" }
98+
, onPress = mkEffectFn1 \_ -> closeSelf
9099
}
91100
, button defaults
92101
{ title = "I can be any element"
93102
, style = R.css { width: "100%" }
103+
, onPress = mkEffectFn1 \_ -> closeSelf
94104
}
95105
]
96106
}
@@ -102,20 +112,23 @@ docs =
102112
{ children:
103113
[ dropdownButton dropdownButtonDefaults
104114
{ label = "Dropdown Button"
105-
, content = R.div
115+
, content = \closeSelf -> R.div
106116
{ style: R.css { width: "328px", padding: "12px" }
107117
, children:
108118
[ button secondary
109119
{ title = "I can be any element"
110120
, style = R.css { width: "100%", marginBottom: "8px" }
121+
, onPress = mkEffectFn1 \_ -> closeSelf
111122
}
112123
, button secondary
113124
{ title = "I can be any element"
114125
, style = R.css { width: "100%", marginBottom: "8px" }
126+
, onPress = mkEffectFn1 \_ -> closeSelf
115127
}
116128
, button defaults
117129
{ title = "I can be any element"
118130
, style = R.css { width: "100%" }
131+
, onPress = mkEffectFn1 \_ -> closeSelf
119132
}
120133
]
121134
}
@@ -201,20 +214,23 @@ docs =
201214
, h2_ "using an arbitrary icon in place of the button"
202215
, example $
203216
dropdownIcon dropdownIconDefaults
204-
{ content = R.div
217+
{ content = \closeSelf -> R.div
205218
{ style: R.css { width: "328px", padding: "12px" }
206219
, children:
207220
[ button secondary
208221
{ title = "I can be any element"
209222
, style = R.css { width: "100%", marginBottom: "8px" }
223+
, onPress = mkEffectFn1 \_ -> closeSelf
210224
}
211225
, button secondary
212226
{ title = "I can be any element"
213227
, style = R.css { width: "100%", marginBottom: "8px" }
228+
, onPress = mkEffectFn1 \_ -> closeSelf
214229
}
215230
, button defaults
216231
{ title = "I can be any element"
217232
, style = R.css { width: "100%" }
233+
, onPress = mkEffectFn1 \_ -> closeSelf
218234
}
219235
]
220236
}

docs/Examples/EditableTable.example.purs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,19 +154,23 @@ docs = unit # make component
154154
[ hspace S16
155155
, dropdownIcon dropdownIconDefaults
156156
{ alignment = Nullable.notNull "right"
157-
, content = R.div
157+
, content = \closeSelf -> R.div
158158
{ style: R.css { width: "328px", padding: "12px" }
159159
, children:
160160
[ Link.link Link.defaults
161161
{ className = pure "lumi-dropdown-menu-item"
162162
, text = p_ "Do something with this row"
163-
, navigate = pure $ log $ "Did something: " <> show row
163+
, navigate = Just do
164+
closeSelf
165+
log $ "Did something: " <> show row
164166
}
165167
, onRemove # Array.foldMap \onRemove' ->
166168
Link.link Link.defaults
167169
{ className = pure "lumi-dropdown-menu-item"
168170
, text = p_ "Remove this row"
169-
, navigate = pure $ onRemove' row
171+
, navigate = Just do
172+
closeSelf
173+
onRemove' row
170174
}
171175
]
172176
}

docs/Examples/InputGroup.example.purs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Prelude
44

55
import Data.Maybe (Maybe(..))
66
import Data.Nullable (toNullable)
7+
import Effect.Uncurried (mkEffectFn1)
78
import Lumi.Components.Button (ButtonState(..), button, defaults, secondary)
89
import Lumi.Components.Column (column_)
910
import Lumi.Components.Input (input, text_)
@@ -44,20 +45,23 @@ docs =
4445
{ children:
4546
[ dropdownButton dropdownButtonDefaults
4647
{ label = "Dropdown Button"
47-
, content = R.div
48+
, content = \closeSelf -> R.div
4849
{ style: R.css { width: "328px", padding: "12px" }
4950
, children:
5051
[ button secondary
5152
{ title = "I can be any element"
5253
, style = R.css { width: "100%", marginBottom: "8px" }
54+
, onPress = mkEffectFn1 \_ -> closeSelf
5355
}
5456
, button secondary
5557
{ title = "I can be any element"
5658
, style = R.css { width: "100%", marginBottom: "8px" }
59+
, onPress = mkEffectFn1 \_ -> closeSelf
5760
}
5861
, button defaults
5962
{ title = "I can be any element"
6063
, style = R.css { width: "100%" }
64+
, onPress = mkEffectFn1 \_ -> closeSelf
6165
}
6266
]
6367
}
@@ -69,20 +73,23 @@ docs =
6973
{ children:
7074
[ dropdownButton dropdownButtonDefaults
7175
{ label = "Dropdown Button"
72-
, content = R.div
76+
, content = \closeSelf -> R.div
7377
{ style: R.css { width: "328px", padding: "12px" }
7478
, children:
7579
[ button secondary
7680
{ title = "I can be any element"
7781
, style = R.css { width: "100%", marginBottom: "8px" }
82+
, onPress = mkEffectFn1 \_ -> closeSelf
7883
}
7984
, button secondary
8085
{ title = "I can be any element"
8186
, style = R.css { width: "100%", marginBottom: "8px" }
87+
, onPress = mkEffectFn1 \_ -> closeSelf
8288
}
8389
, button defaults
8490
{ title = "I can be any element"
8591
, style = R.css { width: "100%" }
92+
, onPress = mkEffectFn1 \_ -> closeSelf
8693
}
8794
]
8895
}

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
"watch": "run-p watch:js watch:purs",
1616
"watch:js": "webpack-dev-server -wd --port 3000 --host 0.0.0.0",
1717
"watch:purs": "pulp -w build -I docs",
18-
"prebuild": "run-s clean eslint",
19-
"build": "run-s build:eslint build:purs build:js",
18+
"prebuild": "run-s eslint",
19+
"build": "run-s build:purs build:js",
2020
"build:js": "webpack -p",
2121
"build:purs": "pulp build -I docs",
2222
"eslint": "eslint --ext .js,.jsx src docs webpack.config.js",

src/Lumi/Components/DropdownButton.purs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,12 @@ import Web.HTML.HTMLElement (HTMLElement, fromNode, getBoundingClientRect, toNod
4141
import Web.HTML.Window (document, innerWidth, scrollX, scrollY) as HTML
4242
import Web.HTML.Window (requestAnimationFrame)
4343

44+
-- | Props for a DropdownButton component. The argument to the `content` field
45+
-- | is a callback which may be called to inform the dropdown button that it
46+
-- | should close itself.
4447
type DropdownButtonProps =
4548
{ label :: String
46-
, content :: JSX
49+
, content :: Effect Unit -> JSX
4750
, className :: String
4851
, onOpen :: Effect Unit
4952
, alignment :: Nullable String
@@ -153,7 +156,7 @@ dropdownButton =
153156
R.css { left: show (state.position.left - 1.0) <> "px" }
154157
]
155158
, onClick: handler stopPropagation mempty
156-
, children: [ props.content ]
159+
, children: [ props.content (close self) ]
157160
}
158161
]
159162
]
@@ -204,14 +207,14 @@ dropdownMenu = makeStateless dropdownMenuComponent render where
204207
, className: "lumi-dropdown-menu " <> className
205208
, alignment: alignment
206209
, onOpen: pure unit
207-
, content:
210+
, content: \closeSelf ->
208211
let
209212
fromItems xs =
210213
column_ $ xs <#> \item ->
211214
Link.link Link.defaults
212215
{ className = pure "lumi-dropdown-menu-item"
213216
, text = p_ item.label
214-
, navigate = pure $ item.action
217+
, navigate = pure $ closeSelf *> item.action
215218
}
216219
in
217220
fragment [ intercalate divider_ (map fromItems items) ]
@@ -236,7 +239,7 @@ dropdownMenuDefaults =
236239

237240
type DropdownIconProps =
238241
{ icon :: JSX
239-
, content :: JSX
242+
, content :: Effect Unit -> JSX
240243
, onOpen :: Effect Unit
241244
, alignment :: Nullable String
242245
}

0 commit comments

Comments
 (0)