git.iko.soy/typeable/elm-ui
on master help sign in
labelHidden
192acf6Matthew Griffith
src/Element/Input.elm+107−44
@@ -6,7 +6,7 @@ module Element.Input exposing
6 , multiline
6 , multiline
7 , slider, Thumb, thumb, defaultThumb
7 , slider, Thumb, thumb, defaultThumb
8 , radio, radioRow, Option, option, optionWith, OptionState(..)
8 , radio, radioRow, Option, option, optionWith, OptionState(..)
9− , Label, labelAbove, labelBelow, labelLeft, labelRight
9+ , Label, labelAbove, labelBelow, labelLeft, labelRight, labelHidden
10 , focusedOnLoad
10 , focusedOnLoad
11 )
11 )
12
12
@@ -43,7 +43,7 @@ We can also give a hint about what type of content our text field contains. This
43
43
44## Labels
44## Labels
45
45
46−@docs Label, labelAbove, labelBelow, labelLeft, labelRight
46+@docs Label, labelAbove, labelBelow, labelLeft, labelRight, labelHidden
47
47
48@docs focusedOnLoad
48@docs focusedOnLoad
49
49
@@ -90,34 +90,68 @@ placeholder =
90 Placeholder
90 Placeholder
91
91
92
92
93+type LabelLocation
94+ = OnRight
95+ | OnLeft
96+ | Above
97+ | Below
98+
99+
93{-| Every input has a required `label`.
100{-| Every input has a required `label`.
94-}
101-}
95type Label msg
102type Label msg
96− = Label Internal.Location (List (Attribute msg)) (Element msg)
103+ = Label LabelLocation (List (Attribute msg)) (Element msg)
104+ | HiddenLabel String
97
105
98
106
99{-| -}
107{-| -}
100labelRight : List (Attribute msg) -> Element msg -> Label msg
108labelRight : List (Attribute msg) -> Element msg -> Label msg
101labelRight =
109labelRight =
102− Label Internal.OnRight
110+ Label OnRight
103
111
104
112
105{-| -}
113{-| -}
106labelLeft : List (Attribute msg) -> Element msg -> Label msg
114labelLeft : List (Attribute msg) -> Element msg -> Label msg
107labelLeft =
115labelLeft =
108− Label Internal.OnLeft
116+ Label OnLeft
109
117
110
118
111{-| -}
119{-| -}
112labelAbove : List (Attribute msg) -> Element msg -> Label msg
120labelAbove : List (Attribute msg) -> Element msg -> Label msg
113labelAbove =
121labelAbove =
114− Label Internal.Above
122+ Label Above
115
123
116
124
117{-| -}
125{-| -}
118labelBelow : List (Attribute msg) -> Element msg -> Label msg
126labelBelow : List (Attribute msg) -> Element msg -> Label msg
119labelBelow =
127labelBelow =
120− Label Internal.Below
128+ Label Below
129+
130+
131+{-| Sometimes you may need to have a label which is not visible, but is still accessible to screen readers.
132+
133+Seriously consider a visible label before using this.
134+
135+The situations where a hidden label makes sense:
136+
137+ - A searchbar with a `search` button right next to it.
138+ - A `table` of inputs where the header gives the label.
139+
140+Basically, a hidden label makes sense when there are other contextual clues that sighted people can pick up on.
141+
142+-}
143+labelHidden : String -> Label msg
144+labelHidden =
145+ HiddenLabel
146+
147+
148+hiddenLabelAttribute label =
149+ case label of
150+ HiddenLabel textLabel ->
151+ Internal.Describe (Internal.Label textLabel)
152+
153+ Label _ _ _ ->
154+ Internal.NoAttribute
121
155
122
156
123{-| A standard button.
157{-| A standard button.
@@ -216,21 +250,30 @@ checkbox :
216checkbox attrs { label, icon, checked, onChange } =
250checkbox attrs { label, icon, checked, onChange } =
217 let
251 let
218 attributes =
252 attributes =
253+ [ if isHiddenLabel label then
254+ Internal.NoAttribute
255+
256+ else
219− Element.spacing 6
257+ Element.spacing
258+ 6
220− :: [ Internal.Attr (Html.Events.onClick (onChange (not checked)))
259+ , Internal.Attr (Html.Events.onClick (onChange (not checked)))
221− , Region.announce
260+ , Region.announce
222− , onKeyLookup <|
261+ , onKeyLookup <|
223− \code ->
262+ \code ->
224− if code == enter then
263+ if code == enter then
225− Just <| onChange (not checked)
264+ Just <| onChange (not checked)
226−
265+
227− else if code == space then
266+ else if code == space then
228− Just <| onChange (not checked)
267+ Just <| onChange (not checked)
229
268
230− else
269+ else
231− Nothing
270+ Nothing
232− ]
271+ , tabindex 0
272+ , Element.pointer
273+ , Element.alignLeft
233− ++ (tabindex 0 :: Element.pointer :: Element.alignLeft :: Element.width Element.fill :: attrs)
274+ , Element.width Element.fill
275+ ]
276+ ++ attrs
234 in
277 in
235 applyLabel attributes
278 applyLabel attributes
236 label
279 label
@@ -246,6 +289,7 @@ checkbox attrs { label, icon, checked, onChange } =
246
289
247 else
290 else
248 "false"
291 "false"
292+ , hiddenLabelAttribute label
249 , Element.centerY
293 , Element.centerY
250 , Element.height Element.fill
294 , Element.height Element.fill
251 , Element.width Element.shrink
295 , Element.width Element.shrink
@@ -428,7 +472,11 @@ slider attributes input =
428 ]
472 ]
429 in
473 in
430 applyLabel
474 applyLabel
475+ [ if isHiddenLabel input.label then
476+ Internal.NoAttribute
477+
478+ else
431− [ Element.spacingXY spacingX spacingY
479+ Element.spacingXY spacingX spacingY
432 , Region.announce
480 , Region.announce
433 , Element.width
481 , Element.width
434 (case trackWidth of
482 (case trackWidth of
@@ -463,7 +511,8 @@ slider attributes input =
463 [ Internal.element
511 [ Internal.element
464 Internal.asEl
512 Internal.asEl
465 (Internal.NodeName "input")
513 (Internal.NodeName "input")
514+ [ hiddenLabelAttribute input.label
466− [ Internal.StyleClass Flag.active
515+ , Internal.StyleClass Flag.active
467 (Internal.Style
516 (Internal.Style
468 ("input[type=\"range\"]." ++ className ++ "::-moz-range-thumb")
517 ("input[type=\"range\"]." ++ className ++ "::-moz-range-thumb")
469 thumbShadowStyle
518 thumbShadowStyle
@@ -891,6 +940,7 @@ textHelper textInput attrs textOptions =
891 (Internal.NodeName inputNode)
940 (Internal.NodeName inputNode)
892 (List.concat
941 (List.concat
893 [ [ focusDefault attrs
942 [ [ focusDefault attrs
943+ , hiddenLabelAttribute textOptions.label
894 ]
944 ]
895 , inputAttrs
945 , inputAttrs
896 , behavior
946 , behavior
@@ -902,7 +952,13 @@ textHelper textInput attrs textOptions =
902 in
952 in
903 applyLabel
953 applyLabel
904 (Internal.Class Flag.cursor classes.cursorText
954 (Internal.Class Flag.cursor classes.cursorText
955+ :: (if isHiddenLabel textOptions.label then
956+ Internal.NoAttribute
957+
958+ else
905− :: Element.spacing 5
959+ Element.spacing
960+ 5
961+ )
906 :: Region.announce
962 :: Region.announce
907 :: attributesFromChild
963 :: attributesFromChild
908 )
964 )
@@ -1130,9 +1186,27 @@ multiline attrs multi =
1130 }
1186 }
1131
1187
1132
1188
1189+isHiddenLabel label =
1190+ case label of
1191+ HiddenLabel _ ->
1192+ True
1193+
1194+ _ ->
1195+ False
1196+
1197+
1133applyLabel : List (Attribute msg) -> Label msg -> Element msg -> Element msg
1198applyLabel : List (Attribute msg) -> Label msg -> Element msg -> Element msg
1134applyLabel attrs label input =
1199applyLabel attrs label input =
1135 case label of
1200 case label of
1201+ HiddenLabel labelText ->
1202+ -- NOTE: This means that the label is applied outside of this function!
1203+ -- It would be nice to unify this logic, but it's a little tricky
1204+ Internal.element
1205+ Internal.asColumn
1206+ (Internal.NodeName "label")
1207+ attrs
1208+ (Internal.Unkeyed [ input ])
1209+
1136 Label position labelAttrs labelChild ->
1210 Label position labelAttrs labelChild ->
1137 let
1211 let
1138 labelElement =
1212 labelElement =
@@ -1143,42 +1217,28 @@ applyLabel attrs label input =
1143 (Internal.Unkeyed [ labelChild ])
1217 (Internal.Unkeyed [ labelChild ])
1144 in
1218 in
1145 case position of
1219 case position of
1146− Internal.Above ->
1220+ Above ->
1147 Internal.element
1221 Internal.element
1148 Internal.asColumn
1222 Internal.asColumn
1149 (Internal.NodeName "label")
1223 (Internal.NodeName "label")
1150 attrs
1224 attrs
1151 (Internal.Unkeyed [ labelElement, input ])
1225 (Internal.Unkeyed [ labelElement, input ])
1152
1226
1153− Internal.Below ->
1227+ Below ->
1154 Internal.element
1228 Internal.element
1155 Internal.asColumn
1229 Internal.asColumn
1156 (Internal.NodeName "label")
1230 (Internal.NodeName "label")
1157 attrs
1231 attrs
1158 (Internal.Unkeyed [ input, labelElement ])
1232 (Internal.Unkeyed [ input, labelElement ])
1159
1233
1160− Internal.OnRight ->
1234+ OnRight ->
1161 Internal.element
1235 Internal.element
1162 Internal.asRow
1236 Internal.asRow
1163 (Internal.NodeName "label")
1237 (Internal.NodeName "label")
1164 attrs
1238 attrs
1165 (Internal.Unkeyed [ input, labelElement ])
1239 (Internal.Unkeyed [ input, labelElement ])
1166
1240
1167− Internal.OnLeft ->
1241+ OnLeft ->
1168− Internal.element
1169− Internal.asRow
1170− (Internal.NodeName "label")
1171− attrs
1172− (Internal.Unkeyed [ labelElement, input ])
1173−
1174− Internal.InFront ->
1175− Internal.element
1176− Internal.asRow
1177− (Internal.NodeName "label")
1178− attrs
1179− (Internal.Unkeyed [ labelElement, input ])
1180−
1181− Internal.Behind ->
1182 Internal.element
1242 Internal.element
1183 Internal.asRow
1243 Internal.asRow
1184 (Internal.NodeName "label")
1244 (Internal.NodeName "label")
@@ -1380,11 +1440,11 @@ radioHelper orientation attrs input =
1380 optionArea =
1440 optionArea =
1381 case orientation of
1441 case orientation of
1382 Row ->
1442 Row ->
1383− row attrs
1443+ row (hiddenLabelAttribute input.label :: attrs)
1384 (List.map renderOption input.options)
1444 (List.map renderOption input.options)
1385
1445
1386 Column ->
1446 Column ->
1387− column attrs
1447+ column (hiddenLabelAttribute input.label :: attrs)
1388 (List.map renderOption input.options)
1448 (List.map renderOption input.options)
1389
1449
1390 prevNext =
1450 prevNext =
@@ -1453,6 +1513,9 @@ radioHelper orientation attrs input =
1453 _ ->
1513 _ ->
1454 False
1514 False
1455
1515
1516+ HiddenLabel _ ->
1517+ True
1518+
1456 hideIfEverythingisInvisible =
1519 hideIfEverythingisInvisible =
1457 if not labelVisible && not inputVisible then
1520 if not labelVisible && not inputVisible then
1458 let
1521 let