git.iko.soy/typeable/elm-ui
on master help sign in
README.md+4
since splitsnapshots
unifiedsplit
@@ -66,6 +66,10 @@ The work is based off of a rewrite of the [Style Elements](https://github.com/md
66
66
67The community around `elm-ui` is maintaining a collection of examples called the [elm-ui-cookbook](https://github.com/rofrol/elm-ui-cookbook). If you are just starting out with `elm-ui`, or get stuck on specific things, this can be a great resource.
67The community around `elm-ui` is maintaining a collection of examples called the [elm-ui-cookbook](https://github.com/rofrol/elm-ui-cookbook). If you are just starting out with `elm-ui`, or get stuck on specific things, this can be a great resource.
68
68
69+## Notes
70+
71+Make sure to have `<!DOCTYPE html>` on top of your application; otherwise, things might get messed up in some browsers.
72+
69## Contributing
73## Contributing
70
74
71Want to help out fixing bugs or reporting issues?
75Want to help out fixing bugs or reporting issues?
elm.json+1−1
@@ -3,7 +3,7 @@
3 "name": "mdgriffith/elm-ui",
3 "name": "mdgriffith/elm-ui",
4 "summary": "Layout and style that's easy to refactor, all without thinking about CSS.",
4 "summary": "Layout and style that's easy to refactor, all without thinking about CSS.",
5 "license": "BSD-3-Clause",
5 "license": "BSD-3-Clause",
6− "version": "1.1.5",
6+ "version": "1.1.8",
7 "exposed-modules": [
7 "exposed-modules": [
8 "Element",
8 "Element",
9 "Element.Input",
9 "Element.Input",
examples/Basic.elm+1−1
@@ -1,4 +1,4 @@
1−module Main exposing (..)
1+module Basic exposing (..)
2
2
3{-| -}
3{-| -}
4
4
examples/Form.elm+12−4
@@ -1,4 +1,4 @@
1−module Main exposing (..)
1+module Form exposing (..)
2
2
3{-| -}
3{-| -}
4
4
@@ -80,7 +80,14 @@ view model =
80 [ Font.size 20
80 [ Font.size 20
81 ]
81 ]
82 <|
82 <|
83− Element.column [ width (px 800), height shrink, centerY, centerX, spacing 36, padding 10, explain Debug.todo ]
83+ Element.column
84+ [ width (px 800)
85+ , height shrink
86+ , centerY
87+ , centerX
88+ , spacing 36
89+ , padding 10
90+ ]
84 [ el
91 [ el
85 [ Region.heading 1
92 [ Region.heading 1
86 , alignLeft
93 , alignLeft
@@ -117,7 +124,7 @@ view model =
117 , onChange = \new -> Update { model | username = new }
124 , onChange = \new -> Update { model | username = new }
118 , label = Input.labelAbove [ Font.size 14 ] (text "Username")
125 , label = Input.labelAbove [ Font.size 14 ] (text "Username")
119 }
126 }
120− , Input.currentPassword [ spacing 12, width shrink ]
127+ , Input.currentPassword [ spacing 12 ]
121 { text = model.password
128 { text = model.password
122 , placeholder = Nothing
129 , placeholder = Nothing
123 , onChange = \new -> Update { model | password = new }
130 , onChange = \new -> Update { model | password = new }
@@ -193,7 +200,8 @@ view model =
193 , Border.color darkBlue
200 , Border.color darkBlue
194 , paddingXY 32 16
201 , paddingXY 32 16
195 , Border.rounded 3
202 , Border.rounded 3
203+
196− , width fill
204+ -- , width fill
197 ]
205 ]
198 { onPress = Nothing
206 { onPress = Nothing
199 , label = Element.text "Place your lunch order!"
207 , label = Element.text "Place your lunch order!"
examples/Table.elm+1−1
@@ -1,4 +1,4 @@
1−module Main exposing (..)
1+module Table exposing (..)
2
2
3{-| -}
3{-| -}
4
4
examples/elm.json+19−22
@@ -1,25 +1,22 @@
1{
1{
2− "type": "application",
2+ "type": "application",
3− "source-directories": [
3+ "source-directories": [".", "../src/"],
4− ".",
5− "../src/"
6− ],
7− "elm-version": "0.19.0",
4+ "elm-version": "0.19.1",
8− "dependencies": {
5+ "dependencies": {
9− "direct": {
6+ "direct": {
10− "elm/browser": "1.0.0",
7+ "elm/browser": "1.0.0",
11− "elm/core": "1.0.0",
8+ "elm/core": "1.0.0",
12− "elm/html": "1.0.0",
9+ "elm/html": "1.0.0",
13− "elm/json": "1.0.0",
10+ "elm/json": "1.0.0",
14− "elm/virtual-dom": "1.0.0"
11+ "elm/virtual-dom": "1.0.0"
15− },
16− "indirect": {
17− "elm/time": "1.0.0",
18− "elm/url": "1.0.0"
19− }
20 },
12 },
21− "test-dependencies": {
22− "direct": {},
23− "indirect": {}
13+ "indirect": {
14+ "elm/time": "1.0.0",
15+ "elm/url": "1.0.0"
24 }
16 }
17+ },
18+ "test-dependencies": {
19+ "direct": {},
20+ "indirect": {}
21+ }
25−}
22+}
package-lock.json+19−31
@@ -734,9 +734,9 @@
734 }
734 }
735 },
735 },
736 "jszip": {
736 "jszip": {
737− "version": "3.2.2",
737+ "version": "3.4.0",
738− "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.2.2.tgz",
738+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.4.0.tgz",
739− "integrity": "sha512-NmKajvAFQpbg3taXQXr/ccS2wcucR1AZ+NtyWp2Nq7HHVsXhcJFR8p0Baf32C2yVvBylFWVeKf+WI2AnvlPhpA==",
739+ "integrity": "sha512-gZAOYuPl4EhPTXT0GjhI3o+ZAz3su6EhLrKUoAivcKqyqC7laS5JEv4XWZND9BgcDcF83vI85yGbDmDR6UhrIg==",
740 "requires": {
740 "requires": {
741 "lie": "~3.3.0",
741 "lie": "~3.3.0",
742 "pako": "~1.0.2",
742 "pako": "~1.0.2",
@@ -1002,20 +1002,24 @@
1002 "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1002 "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1003 "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1003 "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1004 },
1004 },
1005− "sax": {
1006− "version": "1.2.4",
1007− "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
1008− "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
1009− },
1010 "selenium-webdriver": {
1005 "selenium-webdriver": {
1011− "version": "4.0.0-alpha.4",
1006+ "version": "4.0.0-alpha.7",
1012− "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.4.tgz",
1007+ "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.7.tgz",
1013− "integrity": "sha512-etJt20d8qInkxMAHIm5SEpPBSS+CdxVcybnxzSIB/GlWErb8pIWrArz/VA6VfUW0/6tIcokepXQ5ufvdzqqk1A==",
1008+ "integrity": "sha512-D4qnTsyTr91jT8f7MfN+OwY0IlU5+5FmlO5xlgRUV6hDEV8JyYx2NerdTEqDDkNq7RZDYc4VoPALk8l578RBHw==",
1014 "requires": {
1009 "requires": {
1015− "jszip": "^3.1.5",
1010+ "jszip": "^3.2.2",
1016− "rimraf": "^2.6.3",
1011+ "rimraf": "^2.7.1",
1017− "tmp": "0.0.30",
1012+ "tmp": "0.0.30"
1018− "xml2js": "^0.4.19"
1013+ },
1014+ "dependencies": {
1015+ "rimraf": {
1016+ "version": "2.7.1",
1017+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
1018+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
1019+ "requires": {
1020+ "glob": "^7.1.3"
1021+ }
1022+ }
1019 }
1023 }
1020 },
1024 },
1021 "semver": {
1025 "semver": {
@@ -1217,22 +1221,6 @@
1217 "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1221 "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1218 "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
1222 "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
1219 },
1223 },
1220− "xml2js": {
1221− "version": "0.4.19",
1222− "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
1223− "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
1224− "requires": {
1225− "sax": ">=0.6.0",
1226− "xmlbuilder": "~9.0.1"
1227− },
1228− "dependencies": {
1229− "xmlbuilder": {
1230− "version": "9.0.7",
1231− "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
1232− "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
1233− }
1234− }
1235− },
1236 "xmlbuilder": {
1224 "xmlbuilder": {
1237 "version": "13.0.2",
1225 "version": "13.0.2",
1238 "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz",
1226 "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz",
package.json+5−4
@@ -5,12 +5,13 @@
5 "main": "index.js",
5 "main": "index.js",
6 "scripts": {
6 "scripts": {
7 "test": "elm-test",
7 "test": "elm-test",
8+ "view-test": "node tests-rendering/automation/view.js",
8 "test-render": "node tests-rendering/automation/run.js --chrome",
9 "test-render": "node tests-rendering/automation/run.js --chrome",
9− "test-render-sauce": "source sauce.env; node tests-rendering/automation/run.js --sauce",
10+ "test-render-sauce": "source sauce.env; node tests-rendering/automation/run.js --sauce --headless",
10− "test-render-sauce-automated": "node tests-rendering/automation/run.js --sauce",
11+ "test-render-sauce-automated": "node tests-rendering/automation/run.js --sauce --headless",
11 "test-doc-preview": "bash tests-rendering/automation/doc-preview.sh",
12 "test-doc-preview": "bash tests-rendering/automation/doc-preview.sh",
12 "bench": "node benchmarks/runtime/index.js",
13 "bench": "node benchmarks/runtime/index.js",
13− "list-issues": "hub issue -f \"%i,%U,%t%n\" > issues.csv"
14+ "list-issues": "hub issue -f \"%i,%U,%t,'%L'%n\" > issues.csv"
14 },
15 },
15 "repository": {
16 "repository": {
16 "type": "git",
17 "type": "git",
@@ -28,6 +29,6 @@
28 "elm": "^0.19.1-3",
29 "elm": "^0.19.1-3",
29 "elm-test": "^0.19.1-revision2",
30 "elm-test": "^0.19.1-revision2",
30 "node-elm-compiler": "^5.0.4",
31 "node-elm-compiler": "^5.0.4",
31− "selenium-webdriver": "^4.0.0-alpha.4"
32+ "selenium-webdriver": "^4.0.0-alpha.7"
32 }
33 }
33}
34}
src/Element.elm+79−37
@@ -645,14 +645,34 @@ wrappedRow attrs children =
645 newPadding =
645 newPadding =
646 case padded of
646 case padded of
647 Just (Internal.Padding name t r b l) ->
647 Just (Internal.Padding name t r b l) ->
648− if r >= (x // 2) && b >= (y // 2) then
648+ if r >= (toFloat x / 2) && b >= (toFloat y / 2) then
649+ let
650+ newTop =
651+ t - (toFloat y / 2)
652+
653+ newRight =
654+ r - (toFloat x / 2)
655+
656+ newBottom =
657+ b - (toFloat y / 2)
658+
659+ newLeft =
660+ l - (toFloat x / 2)
661+ in
649 Just <|
662 Just <|
650− paddingEach
663+ Internal.StyleClass Flag.padding
651− { top = t - (y // 2)
664+ (Internal.PaddingStyle
652− , right = r - (x // 2)
665+ (Internal.paddingNameFloat
653− , bottom = b - (y // 2)
666+ newTop
654− , left = l - (x // 2)
667+ newRight
655− }
668+ newBottom
669+ newLeft
670+ )
671+ newTop
672+ newRight
673+ newBottom
674+ newLeft
675+ )
656
676
657 else
677 else
658 Nothing
678 Nothing
@@ -988,14 +1008,15 @@ tableHelper attrs config =
988
1008
989{-| A paragraph will layout all children as wrapped, inline elements.
1009{-| A paragraph will layout all children as wrapped, inline elements.
990
1010
991− import Element
1011+ import Element exposing (el, paragraph, text)
992 import Element.Font as Font
1012 import Element.Font as Font
993
1013
1014+ view =
994− Element.paragraph []
1015+ paragraph []
995− [ text "lots of text ...."
1016+ [ text "lots of text ...."
996− , el [ Font.bold ] (text "this is bold")
1017+ , el [ Font.bold ] (text "this is bold")
997− , text "lots of text ...."
1018+ , text "lots of text ...."
998− ]
1019+ ]
999
1020
1000This is really useful when you want to markup text by having some parts be bold, or some be links, or whatever you so desire.
1021This is really useful when you want to markup text by having some parts be bold, or some be links, or whatever you so desire.
1001
1022
@@ -1003,17 +1024,18 @@ Also, if a child element has `alignLeft` or `alignRight`, then it will be moved
1003
1024
1004This makes it particularly easy to do something like a [dropped capital](https://en.wikipedia.org/wiki/Initial).
1025This makes it particularly easy to do something like a [dropped capital](https://en.wikipedia.org/wiki/Initial).
1005
1026
1006− import Element
1027+ import Element exposing (alignLeft, el, padding, paragraph, text)
1007 import Element.Font as Font
1028 import Element.Font as Font
1008
1029
1009− Element.paragraph []
1030+ view =
1031+ paragraph []
1010− [ el
1032+ [ el
1011− [ alignLeft
1033+ [ alignLeft
1012− , padding 5
1034+ , padding 5
1035+ ]
1036+ (text "S")
1037+ , text "o much text ...."
1013 ]
1038 ]
1014− (text "S")
1015− , text "o much text ...."
1016− ]
1017
1039
1018Which will look something like
1040Which will look something like
1019
1041
@@ -1181,11 +1203,6 @@ newTabLink attrs { url, label } =
1181
1203
1182
1204
1183{-| A link to download a file.
1205{-| A link to download a file.
1184−
1185−**Note** If you're using `Browser.application`, then this won't be enough to actually trigger a file download due to how `Browser.Navigation` works.
1186−
1187−[Here's a description of what needs to happen](https://github.com/elm/html/issues/175).
1188−
1189-}
1206-}
1190download :
1207download :
1191 List (Attribute msg)
1208 List (Attribute msg)
@@ -1341,7 +1358,11 @@ moveLeft x =
1341{-| -}
1358{-| -}
1342padding : Int -> Attribute msg
1359padding : Int -> Attribute msg
1343padding x =
1360padding x =
1361+ let
1362+ f =
1363+ toFloat x
1364+ in
1344− Internal.StyleClass Flag.padding (Internal.PaddingStyle ("p-" ++ String.fromInt x) x x x x)
1365+ Internal.StyleClass Flag.padding (Internal.PaddingStyle ("p-" ++ String.fromInt x) f f f f)
1345
1366
1346
1367
1347{-| Set horizontal and vertical padding.
1368{-| Set horizontal and vertical padding.
@@ -1349,16 +1370,27 @@ padding x =
1349paddingXY : Int -> Int -> Attribute msg
1370paddingXY : Int -> Int -> Attribute msg
1350paddingXY x y =
1371paddingXY x y =
1351 if x == y then
1372 if x == y then
1373+ let
1374+ f =
1375+ toFloat x
1376+ in
1352− Internal.StyleClass Flag.padding (Internal.PaddingStyle ("p-" ++ String.fromInt x) x x x x)
1377+ Internal.StyleClass Flag.padding (Internal.PaddingStyle ("p-" ++ String.fromInt x) f f f f)
1353
1378
1354 else
1379 else
1380+ let
1381+ xFloat =
1382+ toFloat x
1383+
1384+ yFloat =
1385+ toFloat y
1386+ in
1355 Internal.StyleClass Flag.padding
1387 Internal.StyleClass Flag.padding
1356 (Internal.PaddingStyle
1388 (Internal.PaddingStyle
1357 ("p-" ++ String.fromInt x ++ "-" ++ String.fromInt y)
1389 ("p-" ++ String.fromInt x ++ "-" ++ String.fromInt y)
1358− y
1390+ yFloat
1359− x
1391+ xFloat
1360− y
1392+ yFloat
1361− x
1393+ xFloat
1362 )
1394 )
1363
1395
1364
1396
@@ -1379,16 +1411,26 @@ And then just do
1379paddingEach : { top : Int, right : Int, bottom : Int, left : Int } -> Attribute msg
1411paddingEach : { top : Int, right : Int, bottom : Int, left : Int } -> Attribute msg
1380paddingEach { top, right, bottom, left } =
1412paddingEach { top, right, bottom, left } =
1381 if top == right && top == bottom && top == left then
1413 if top == right && top == bottom && top == left then
1414+ let
1415+ topFloat =
1416+ toFloat top
1417+ in
1418+ Internal.StyleClass Flag.padding
1382− Internal.StyleClass Flag.padding (Internal.PaddingStyle ("p-" ++ String.fromInt top) top top top top)
1419+ (Internal.PaddingStyle ("p-" ++ String.fromInt top)
1420+ topFloat
1421+ topFloat
1422+ topFloat
1423+ topFloat
1424+ )
1383
1425
1384 else
1426 else
1385 Internal.StyleClass Flag.padding
1427 Internal.StyleClass Flag.padding
1386 (Internal.PaddingStyle
1428 (Internal.PaddingStyle
1387 (Internal.paddingName top right bottom left)
1429 (Internal.paddingName top right bottom left)
1388− top
1430+ (toFloat top)
1389− right
1431+ (toFloat right)
1390− bottom
1432+ (toFloat bottom)
1391− left
1433+ (toFloat left)
1392 )
1434 )
1393
1435
1394
1436
src/Element/Input.elm+75−40
@@ -132,10 +132,12 @@ Instead of implicit submission behavior, [try making an `onEnter` event handler
132
132
133And no one has to look up obtuse html documentation to understand the behavior of their code :).
133And no one has to look up obtuse html documentation to understand the behavior of their code :).
134
134
135+
135# File Inputs
136# File Inputs
136
137
137Presently, elm-ui does not expose a replacement for `<input type="file">`; in the meantime, an `Input.button` and `elm/file`'s `File.Select` may meet your needs.
138Presently, elm-ui does not expose a replacement for `<input type="file">`; in the meantime, an `Input.button` and `elm/file`'s `File.Select` may meet your needs.
138
139
140+
139# Disabling Inputs
141# Disabling Inputs
140
142
141You also might be wondering how to disable an input.
143You also might be wondering how to disable an input.
@@ -328,6 +330,8 @@ The `onPress` handler will be fired either `onClick` or when the element is focu
328 , label = text "My Button"
330 , label = text "My Button"
329 }
331 }
330
332
333+**Note** If you have an icon button but want it to be accessible, consider adding a [`Region.description`](Element-Region#description), which will describe the button to screen readers.
334+
331-}
335-}
332button :
336button :
333 List (Attribute msg)
337 List (Attribute msg)
@@ -365,7 +369,17 @@ button attrs { onPress, label } =
365
369
366 Just msg ->
370 Just msg ->
367 Events.onClick msg
371 Events.onClick msg
368− :: onEnter msg
372+ :: onKeyLookup
373+ (\code ->
374+ if code == enter then
375+ Just msg
376+
377+ else if code == space then
378+ Just msg
379+
380+ else
381+ Nothing
382+ )
369 :: attrs
383 :: attrs
370 )
384 )
371 )
385 )
@@ -443,22 +457,24 @@ checkbox attrs { label, icon, checked, onChange } =
443 ]
457 ]
444 ++ attrs
458 ++ attrs
445 in
459 in
446− applyLabel attributes
460+ applyLabel
447− label
448− (Internal.element
449− Internal.asEl
450− Internal.div
451− [ Internal.Attr <|
452− Html.Attributes.attribute "role" "checkbox"
461+ (Internal.Attr (Html.Attributes.attribute "role" "checkbox")
453− , Internal.Attr <|
462+ :: Internal.Attr
454− Html.Attributes.attribute "aria-checked" <|
463+ (Html.Attributes.attribute "aria-checked" <|
455 if checked then
464 if checked then
456 "true"
465 "true"
457
466
458 else
467 else
459 "false"
468 "false"
469+ )
460− , hiddenLabelAttribute label
470+ :: hiddenLabelAttribute label
471+ :: attributes
472+ )
473+ label
474+ (Internal.element
475+ Internal.asEl
476+ Internal.div
461− , Element.centerY
477+ [ Element.centerY
462 , Element.height Element.fill
478 , Element.height Element.fill
463 , Element.width Element.shrink
479 , Element.width Element.shrink
464 ]
480 ]
@@ -697,7 +713,7 @@ slider attributes input =
697 ("input[type=\"range\"]." ++ className ++ "::-ms-thumb")
713 ("input[type=\"range\"]." ++ className ++ "::-ms-thumb")
698 thumbShadowStyle
714 thumbShadowStyle
699 )
715 )
700− , Internal.Attr (Html.Attributes.class (className ++ " focusable-parent"))
716+ , Internal.Attr (Html.Attributes.class (className ++ " ui-slide-bar focusable-parent"))
701 , Internal.Attr
717 , Internal.Attr
702 (Html.Events.onInput
718 (Html.Events.onInput
703 (\str ->
719 (\str ->
@@ -763,10 +779,10 @@ slider attributes input =
763 -- This is after `attributes` because the thumb should be in front of everything.
779 -- This is after `attributes` because the thumb should be in front of everything.
764 ++ [ Element.behindContent <|
780 ++ [ Element.behindContent <|
765 if vertical then
781 if vertical then
766− viewVerticalThumb factor thumbAttributes trackWidth
782+ viewVerticalThumb factor (Internal.htmlClass "focusable-thumb" :: thumbAttributes) trackWidth
767
783
768 else
784 else
769− viewHorizontalThumb factor thumbAttributes trackHeight
785+ viewHorizontalThumb factor (Internal.htmlClass "focusable-thumb" :: thumbAttributes) trackHeight
770 ]
786 ]
771 )
787 )
772 Element.none
788 Element.none
@@ -866,10 +882,10 @@ textHelper textInput attrs textOptions =
866 -- when things are off by a pixel or two.
882 -- when things are off by a pixel or two.
867 -- (or at least when the browser *thinks* it's off by a pixel or two)
883 -- (or at least when the browser *thinks* it's off by a pixel or two)
868 Just
884 Just
869− { top = max 0 (floor (toFloat t - 3))
885+ { top = max 0 (floor (t - 3))
870− , right = max 0 (floor (toFloat r - 3))
886+ , right = max 0 (floor (r - 3))
871− , bottom = max 0 (floor (toFloat b - 3))
887+ , bottom = max 0 (floor (b - 3))
872− , left = max 0 (floor (toFloat l - 3))
888+ , left = max 0 (floor (l - 3))
873 }
889 }
874
890
875 _ ->
891 _ ->
@@ -1312,23 +1328,36 @@ redistributeOver isMultiline stacked attr els =
1312 Element.htmlAttribute
1328 Element.htmlAttribute
1313 (Html.Attributes.style
1329 (Html.Attributes.style
1314 "height"
1330 "height"
1315− ("calc(1.0em + " ++ String.fromInt (2 * min t b) ++ "px)")
1331+ ("calc(1.0em + " ++ String.fromFloat (2 * min t b) ++ "px)")
1316 )
1332 )
1317
1333
1318 newLineHeight =
1334 newLineHeight =
1319 Element.htmlAttribute
1335 Element.htmlAttribute
1320 (Html.Attributes.style
1336 (Html.Attributes.style
1321 "line-height"
1337 "line-height"
1322− ("calc(1.0em + " ++ String.fromInt (2 * min t b) ++ "px)")
1338+ ("calc(1.0em + " ++ String.fromFloat (2 * min t b) ++ "px)")
1323 )
1339 )
1324
1340
1341+ newTop =
1342+ t - min t b
1343+
1344+ newBottom =
1345+ b - min t b
1346+
1325 reducedVerticalPadding =
1347 reducedVerticalPadding =
1326− Element.paddingEach
1348+ Internal.StyleClass Flag.padding
1327− { top = t - min t b
1349+ (Internal.PaddingStyle
1328− , right = r
1350+ (Internal.paddingNameFloat
1329− , bottom = b - min t b
1351+ newTop
1330− , left = l
1352+ r
1331− }
1353+ newBottom
1354+ l
1355+ )
1356+ newTop
1357+ r
1358+ newBottom
1359+ l
1360+ )
1332 in
1361 in
1333 { els
1362 { els
1334 | parent = reducedVerticalPadding :: els.parent
1363 | parent = reducedVerticalPadding :: els.parent
@@ -1536,6 +1565,8 @@ email =
1536
1565
1537By default it will have a minimum height of one line and resize based on it's contents.
1566By default it will have a minimum height of one line and resize based on it's contents.
1538
1567
1568+Use `Element.spacing` to change its line-height.
1569+
1539-}
1570-}
1540multiline :
1571multiline :
1541 List (Attribute msg)
1572 List (Attribute msg)
@@ -1597,28 +1628,28 @@ applyLabel attrs label input =
1597 Internal.element
1628 Internal.element
1598 Internal.asColumn
1629 Internal.asColumn
1599 (Internal.NodeName "label")
1630 (Internal.NodeName "label")
1600− attrs
1631+ (Internal.htmlClass classes.inputLabel :: attrs)
1601 (Internal.Unkeyed [ labelElement, input ])
1632 (Internal.Unkeyed [ labelElement, input ])
1602
1633
1603 Below ->
1634 Below ->
1604 Internal.element
1635 Internal.element
1605 Internal.asColumn
1636 Internal.asColumn
1606 (Internal.NodeName "label")
1637 (Internal.NodeName "label")
1607− attrs
1638+ (Internal.htmlClass classes.inputLabel :: attrs)
1608 (Internal.Unkeyed [ input, labelElement ])
1639 (Internal.Unkeyed [ input, labelElement ])
1609
1640
1610 OnRight ->
1641 OnRight ->
1611 Internal.element
1642 Internal.element
1612 Internal.asRow
1643 Internal.asRow
1613 (Internal.NodeName "label")
1644 (Internal.NodeName "label")
1614− attrs
1645+ (Internal.htmlClass classes.inputLabel :: attrs)
1615 (Internal.Unkeyed [ input, labelElement ])
1646 (Internal.Unkeyed [ input, labelElement ])
1616
1647
1617 OnLeft ->
1648 OnLeft ->
1618 Internal.element
1649 Internal.element
1619 Internal.asRow
1650 Internal.asRow
1620 (Internal.NodeName "label")
1651 (Internal.NodeName "label")
1621− attrs
1652+ (Internal.htmlClass classes.inputLabel :: attrs)
1622 (Internal.Unkeyed [ labelElement, input ])
1653 (Internal.Unkeyed [ labelElement, input ])
1623
1654
1624
1655
@@ -2074,7 +2105,11 @@ onKeyLookup lookup =
2074 Json.field "key" Json.string
2105 Json.field "key" Json.string
2075 |> Json.andThen decode
2106 |> Json.andThen decode
2076 in
2107 in
2108+ -- We generally want these attached to the keydown event becaues it allows us to prevent default on things like spacebar scrolling the page.
2109+ -- https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role
2077− Internal.Attr <| Html.Events.on "keyup" isKey
2110+ Internal.Attr <|
2111+ Html.Events.preventDefaultOn "keydown"
2112+ (Json.map (\fired -> ( fired, True )) isKey)
2078
2113
2079
2114
2080{-| -}
2115{-| -}
@@ -2170,7 +2205,8 @@ defaultCheckbox : Bool -> Element msg
2170defaultCheckbox checked =
2205defaultCheckbox checked =
2171 Element.el
2206 Element.el
2172 [ Internal.htmlClass "focusable"
2207 [ Internal.htmlClass "focusable"
2173− , Element.width (Element.px 14)
2208+ , Element.width
2209+ (Element.px 14)
2174 , Element.height (Element.px 14)
2210 , Element.height (Element.px 14)
2175 , Font.color white
2211 , Font.color white
2176 , Element.centerY
2212 , Element.centerY
@@ -2206,9 +2242,8 @@ defaultCheckbox checked =
2206
2242
2207 else
2243 else
2208 1
2244 1
2209− ]
2245+ , Element.inFront
2210− (if checked then
2211− Element.el
2246+ (Element.el
2212 [ Border.color white
2247 [ Border.color white
2213 , Element.height (Element.px 6)
2248 , Element.height (Element.px 6)
2214 , Element.width (Element.px 9)
2249 , Element.width (Element.px 9)
@@ -2216,6 +2251,7 @@ defaultCheckbox checked =
2216 , Element.centerX
2251 , Element.centerX
2217 , Element.centerY
2252 , Element.centerY
2218 , Element.moveUp 1
2253 , Element.moveUp 1
2254+ , Element.transparent (not checked)
2219 , Border.widthEach
2255 , Border.widthEach
2220 { top = 0
2256 { top = 0
2221 , left = 2
2257 , left = 2
@@ -2224,7 +2260,6 @@ defaultCheckbox checked =
2224 }
2260 }
2225 ]
2261 ]
2226 Element.none
2262 Element.none
2227−
2263+ )
2228− else
2264+ ]
2229− Element.none
2265+ Element.none
2230− )
src/Element/Region.elm+5−1
@@ -101,7 +101,11 @@ announce =
101 Internal.Describe LivePolite
101 Internal.Describe LivePolite
102
102
103
103
104+{-| Adds an `aria-label`, which is used by accessibility software to identity otherwise unlabeled elements.
105+
106+A common use for this would be to label buttons that only have an icon.
107+
104−{-| -}
108+-}
105description : String -> Attribute msg
109description : String -> Attribute msg
106description =
110description =
107 Internal.Describe << Internal.Label
111 Internal.Describe << Internal.Label
src/Internal/Model.elm+30−32
@@ -79,6 +79,7 @@ module Internal.Model exposing
79 , onlyStyles
79 , onlyStyles
80 , optionsToRecord
80 , optionsToRecord
81 , paddingName
81 , paddingName
82+ , paddingNameFloat
82 , pageClass
83 , pageClass
83 , paragraphClass
84 , paragraphClass
84 , reduceRecursive
85 , reduceRecursive
@@ -173,7 +174,7 @@ type Style
173 | Colored String String Color
174 | Colored String String Color
174 | SpacingStyle String Int Int
175 | SpacingStyle String Int Int
175 | BorderWidth String Int Int Int Int
176 | BorderWidth String Int Int Int Int
176− | PaddingStyle String Int Int Int Int
177+ | PaddingStyle String Float Float Float Float
177 | GridTemplateStyle
178 | GridTemplateStyle
178 { spacing : ( Length, Length )
179 { spacing : ( Length, Length )
179 , columns : List Length
180 , columns : List Length
@@ -1477,7 +1478,9 @@ renderHeight h =
1477 Single
1478 Single
1478 cls
1479 cls
1479 "min-height"
1480 "min-height"
1481+ -- This needs to be !important because we're using `min-height: min-content`
1482+ -- to correct for safari's incorrect implementation of flexbox.
1480− (String.fromInt minSize ++ "px")
1483+ (String.fromInt minSize ++ "px !important")
1481
1484
1482 ( newFlag, newAttrs, newStyle ) =
1485 ( newFlag, newAttrs, newStyle ) =
1483 renderHeight len
1486 renderHeight len
@@ -1945,7 +1948,7 @@ type Spacing
1945
1948
1946
1949
1947type Padding
1950type Padding
1948− = Padding String Int Int Int Int
1951+ = Padding String Float Float Float Float
1949
1952
1950
1953
1951extractSpacingAndPadding : List (Attribute aligned msg) -> ( Maybe Padding, Maybe Spacing )
1954extractSpacingAndPadding : List (Attribute aligned msg) -> ( Maybe Padding, Maybe Spacing )
@@ -2241,7 +2244,11 @@ renderFocusStyle focus =
2241 , Just <| Property "outline" "none"
2244 , Just <| Property "outline" "none"
2242 ]
2245 ]
2243 )
2246 )
2247+ , Style
2244− , Style (Internal.Style.dot classes.any ++ ":focus .focusable, " ++ Internal.Style.dot classes.any ++ ".focusable:focus")
2248+ ((Internal.Style.dot classes.any ++ ":focus .focusable, ")
2249+ ++ (Internal.Style.dot classes.any ++ ".focusable:focus, ")
2250+ ++ (".ui-slide-bar:focus + " ++ Internal.Style.dot classes.any ++ " .focusable-thumb")
2251+ )
2245 (List.filterMap identity
2252 (List.filterMap identity
2246 [ Maybe.map (\color -> Property "border-color" (formatColor color)) focus.borderColor
2253 [ Maybe.map (\color -> Property "border-color" (formatColor color)) focus.borderColor
2247 , Maybe.map (\color -> Property "background-color" (formatColor color)) focus.backgroundColor
2254 , Maybe.map (\color -> Property "background-color" (formatColor color)) focus.backgroundColor
@@ -2642,34 +2649,14 @@ renderStyle options maybePseudo selector props =
2642 renderedProps =
2649 renderedProps =
2643 List.foldl (renderProps False) "" props
2650 List.foldl (renderProps False) "" props
2644 in
2651 in
2645− [ selector
2646− ++ "-fs:focus {"
2647− ++ renderedProps
2652+ [ selector ++ "-fs:focus {" ++ renderedProps ++ "\n}"
2648− ++ "\n}"
2649− , "."
2650− ++ classes.any
2653+ , ("." ++ classes.any ++ ":focus " ++ selector ++ "-fs {")
2651− ++ ":focus ~ "
2652− ++ selector
2653− ++ "-fs:not(.focus) {"
2654 ++ renderedProps
2654 ++ renderedProps
2655 ++ "\n}"
2655 ++ "\n}"
2656− , "."
2656+ , (selector ++ "-fs:focus-within {")
2657− ++ classes.any
2658− ++ ":focus "
2659− ++ selector
2660− ++ "-fs {"
2661 ++ renderedProps
2657 ++ renderedProps
2662 ++ "\n}"
2658 ++ "\n}"
2663− , selector
2659+ , (".ui-slide-bar:focus + " ++ Internal.Style.dot classes.any ++ " .focusable-thumb" ++ selector ++ "-fs {")
2664− ++ "-fs:focus-within {"
2665− ++ renderedProps
2666− ++ "\n}"
2667− , ".focusable-parent:focus ~ "
2668− ++ "."
2669− ++ classes.any
2670− ++ " "
2671− ++ selector
2672− ++ "-fs {"
2673 ++ renderedProps
2660 ++ renderedProps
2674 ++ "\n}"
2661 ++ "\n}"
2675 ]
2662 ]
@@ -2876,13 +2863,13 @@ renderStyleRule options rule maybePseudo =
2876 maybePseudo
2863 maybePseudo
2877 class
2864 class
2878 [ Property "padding"
2865 [ Property "padding"
2879− (String.fromInt top
2866+ (String.fromFloat top
2880 ++ "px "
2867 ++ "px "
2881− ++ String.fromInt right
2868+ ++ String.fromFloat right
2882 ++ "px "
2869 ++ "px "
2883− ++ String.fromInt bottom
2870+ ++ String.fromFloat bottom
2884 ++ "px "
2871 ++ "px "
2885− ++ String.fromInt left
2872+ ++ String.fromFloat left
2886 ++ "px"
2873 ++ "px"
2887 )
2874 )
2888 ]
2875 ]
@@ -3212,6 +3199,17 @@ paddingName top right bottom left =
3212 ++ String.fromInt left
3199 ++ String.fromInt left
3213
3200
3214
3201
3202+paddingNameFloat top right bottom left =
3203+ "pad-"
3204+ ++ floatClass top
3205+ ++ "-"
3206+ ++ floatClass right
3207+ ++ "-"
3208+ ++ floatClass bottom
3209+ ++ "-"
3210+ ++ floatClass left
3211+
3212+
3215getStyleName : Style -> String
3213getStyleName : Style -> String
3216getStyleName style =
3214getStyleName style =
3217 case style of
3215 case style of
src/Internal/Style.elm+63−16
@@ -10,6 +10,7 @@ type Class
10type Rule
10type Rule
11 = Prop String String
11 = Prop String String
12 | Child String (List Rule)
12 | Child String (List Rule)
13+ | AllChildren String (List Rule)
13 | Supports ( String, String ) (List ( String, String ))
14 | Supports ( String, String ) (List ( String, String ))
14 | Descriptor String (List Rule)
15 | Descriptor String (List Rule)
15 | Adjacent String (List Rule)
16 | Adjacent String (List Rule)
@@ -256,6 +257,7 @@ classes =
256 , inputMultilineParent = "imlp"
257 , inputMultilineParent = "imlp"
257 , inputMultilineFiller = "imlf"
258 , inputMultilineFiller = "imlf"
258 , inputMultilineWrapper = "implw"
259 , inputMultilineWrapper = "implw"
260+ , inputLabel = "lbl"
259
261
260 -- link
262 -- link
261 , link = "lnk"
263 , link = "lnk"
@@ -560,6 +562,15 @@ renderRules (Intermediate parent) rulesToRender =
560 :: rendered.others
562 :: rendered.others
561 }
563 }
562
564
565+ AllChildren child childRules ->
566+ { rendered
567+ | others =
568+ renderRules
569+ (emptyIntermediate (parent.selector ++ " " ++ child) "")
570+ childRules
571+ :: rendered.others
572+ }
573+
563 Descriptor descriptor descriptorRules ->
574 Descriptor descriptor descriptorRules ->
564 { rendered
575 { rendered
565 | others =
576 | others =
@@ -950,6 +961,18 @@ baseSheet =
950 ]
961 ]
951 , Class (dot classes.any ++ dot classes.single ++ dot classes.imageContainer)
962 , Class (dot classes.any ++ dot classes.single ++ dot classes.imageContainer)
952 [ Prop "display" "block"
963 [ Prop "display" "block"
964+ , Descriptor (dot classes.heightFill)
965+ [ Child "img"
966+ [ Prop "max-height" "100%"
967+ , Prop "object-fit" "cover"
968+ ]
969+ ]
970+ , Descriptor (dot classes.widthFill)
971+ [ Child "img"
972+ [ Prop "max-width" "100%"
973+ , Prop "object-fit" "cover"
974+ ]
975+ ]
953 ]
976 ]
954 , Class (dot classes.any ++ ":focus")
977 , Class (dot classes.any ++ ":focus")
955 [ Prop "outline" "none"
978 [ Prop "outline" "none"
@@ -972,6 +995,7 @@ baseSheet =
972 , Child (dot classes.inFront)
995 , Child (dot classes.inFront)
973 [ Descriptor (dot classes.nearby)
996 [ Descriptor (dot classes.nearby)
974 [ Prop "position" "fixed"
997 [ Prop "position" "fixed"
998+ , Prop "z-index" "20"
975 ]
999 ]
976 ]
1000 ]
977 ]
1001 ]
@@ -1220,6 +1244,7 @@ baseSheet =
1220 -- If it's 1, it bumps up to something like 1.2
1244 -- If it's 1, it bumps up to something like 1.2
1221 [ Prop "line-height" "1.05"
1245 [ Prop "line-height" "1.05"
1222 , Prop "background" "transparent"
1246 , Prop "background" "transparent"
1247+ , Prop "text-align" "inherit"
1223 ]
1248 ]
1224 , Descriptor (dot classes.single)
1249 , Descriptor (dot classes.single)
1225 elDescription
1250 elDescription
@@ -1346,18 +1371,28 @@ baseSheet =
1346 , Descriptor (dot classes.spaceEvenly)
1371 , Descriptor (dot classes.spaceEvenly)
1347 [ Prop "justify-content" "space-between"
1372 [ Prop "justify-content" "space-between"
1348 ]
1373 ]
1374+ , Descriptor (dot classes.inputLabel)
1375+ [ Prop "align-items" "baseline"
1376+ ]
1349 ]
1377 ]
1350 , Descriptor (dot classes.column)
1378 , Descriptor (dot classes.column)
1351 [ Prop "display" "flex"
1379 [ Prop "display" "flex"
1352 , Prop "flex-direction" "column"
1380 , Prop "flex-direction" "column"
1353 , Child (dot classes.any)
1381 , Child (dot classes.any)
1382+ -- *Note* - While rows have flex-basis 0%,
1383+ -- which allows for the children of a row to default to their content size
1384+ -- This apparently is a different story for columns.
1385+ -- Safari has an issue if this is flex-basis: 0%, as it goes entirely to 0,
1386+ -- instead of the expected content size.
1387+ -- So we add `min-height: min-content`, which isn't supported by IE, but works for all other browsers!
1388+ -- Separately, 0% is different than 0px, but only for columns
1389+ -- In columns, 0% will actually be calculated as `auto` for columns
1390+ -- So, 0px is the one we want.
1354− [ Prop "flex-basis" "0%"
1391+ [ Prop "flex-basis" "0px"
1392+ , Prop "min-height" "min-content"
1355 , Descriptor (dot classes.heightExact)
1393 , Descriptor (dot classes.heightExact)
1356 [ Prop "flex-basis" "auto"
1394 [ Prop "flex-basis" "auto"
1357 ]
1395 ]
1358− , Descriptor (dot classes.column)
1359− [ Prop "flex-basis" "auto"
1360− ]
1361 ]
1396 ]
1362 , Child (dot classes.heightFill)
1397 , Child (dot classes.heightFill)
1363 [ Prop "flex-grow" "100000"
1398 [ Prop "flex-grow" "100000"
@@ -1561,7 +1596,7 @@ baseSheet =
1561 )
1596 )
1562 ]
1597 ]
1563 , Descriptor (dot classes.inputMultiline)
1598 , Descriptor (dot classes.inputMultiline)
1564− [ Prop "white-space" "pre-wrap"
1599+ [ Prop "white-space" "pre-wrap !important"
1565 , Prop "height" "100%"
1600 , Prop "height" "100%"
1566 , Prop "width" "100%"
1601 , Prop "width" "100%"
1567 , Prop "background-color" "transparent"
1602 , Prop "background-color" "transparent"
@@ -1581,29 +1616,47 @@ baseSheet =
1581 [ Prop "flex-basis" "auto" ]
1616 [ Prop "flex-basis" "auto" ]
1582 ]
1617 ]
1583 , Descriptor (dot classes.inputMultilineParent)
1618 , Descriptor (dot classes.inputMultilineParent)
1584− [ Prop "white-space" "pre-wrap"
1619+ [ Prop "white-space" "pre-wrap !important"
1585 , Prop "cursor" "text"
1620 , Prop "cursor" "text"
1586 , Child (dot classes.inputMultilineFiller)
1621 , Child (dot classes.inputMultilineFiller)
1587− [ Prop "white-space" "pre-wrap"
1622+ [ Prop "white-space" "pre-wrap !important"
1588 , Prop "color" "transparent"
1623 , Prop "color" "transparent"
1589 ]
1624 ]
1590 ]
1625 ]
1591 , Descriptor (dot classes.paragraph)
1626 , Descriptor (dot classes.paragraph)
1592 [ Prop "display" "block"
1627 [ Prop "display" "block"
1593 , Prop "white-space" "normal"
1628 , Prop "white-space" "normal"
1629+ , Prop "overflow-wrap" "break-word"
1594 , Descriptor (dot classes.hasBehind)
1630 , Descriptor (dot classes.hasBehind)
1595 [ Prop "z-index" "0"
1631 [ Prop "z-index" "0"
1596 , Child (dot classes.behind)
1632 , Child (dot classes.behind)
1597 [ Prop "z-index" "-1"
1633 [ Prop "z-index" "-1"
1598 ]
1634 ]
1599 ]
1635 ]
1600− , Child (dot classes.text)
1636+ , AllChildren (dot classes.text)
1601 [ Prop "display" "inline"
1637 [ Prop "display" "inline"
1602 , Prop "white-space" "normal"
1638 , Prop "white-space" "normal"
1603 ]
1639 ]
1640+ , AllChildren (dot classes.paragraph)
1641+ [ Prop "display" "inline"
1642+ , Descriptor "::after"
1643+ [ Prop "content" "none"
1644+ ]
1645+ , Descriptor "::before"
1646+ [ Prop "content" "none"
1647+ ]
1648+ ]
1604− , Child (dot classes.single)
1649+ , AllChildren (dot classes.single)
1605 [ Prop "display" "inline"
1650 [ Prop "display" "inline"
1606 , Prop "white-space" "normal"
1651 , Prop "white-space" "normal"
1652+
1653+ -- Inline block allows the width of the item to be set
1654+ -- but DOES NOT like wrapping text in a standard, normal, sane way.
1655+ -- We're sorta counting that if an exact width has been set,
1656+ -- people aren't expecting proper text wrapping for this element
1657+ , Descriptor (dot classes.widthExact)
1658+ [ Prop "display" "inline-block"
1659+ ]
1607 , Descriptor (dot classes.inFront)
1660 , Descriptor (dot classes.inFront)
1608 [ Prop "display" "flex"
1661 [ Prop "display" "flex"
1609 ]
1662 ]
@@ -1626,15 +1679,9 @@ baseSheet =
1626 [ Prop "display" "inline"
1679 [ Prop "display" "inline"
1627 , Prop "white-space" "normal"
1680 , Prop "white-space" "normal"
1628 ]
1681 ]
1629− , Child (dot classes.single)
1630− [ Child (dot classes.text)
1631− [ Prop "display" "inline"
1632− , Prop "white-space" "normal"
1633− ]
1634− ]
1635 ]
1682 ]
1636 , Child (dot classes.row)
1683 , Child (dot classes.row)
1637− [ Prop "display" "inline-flex"
1684+ [ Prop "display" "inline"
1638 ]
1685 ]
1639 , Child (dot classes.column)
1686 , Child (dot classes.column)
1640 [ Prop "display" "inline-flex"
1687 [ Prop "display" "inline-flex"
tests-rendering/automation/build.jsnew file+90
@@ -0,0 +1,90 @@
1+const fs = require("fs");
2+const path = require("path");
3+const compileToString = require("node-elm-compiler").compileToString;
4+
5+// {
6+// template: "./tests-rendering/automation/templates/gather-styles.html",
7+// target: "./tmp/test.html",
8+// elm: "src/Tests/Run.elm",
9+// replace:
10+// elmOptions: { cwd: "./tests-rendering" },
11+// }
12+
13+async function compile_and_embed(config) {
14+ const elm_entry_module = fs.readFileSync(
15+ path.join(config.elmOptions.cwd, config.elm),
16+ "utf8"
17+ );
18+
19+ const module_name = elm_entry_module
20+ .split(/[\r\n]+/)[0]
21+ .match(/module ([A-Za-z0-9\.]+)/i)[1];
22+
23+ // we embed the compiled js to avoid having to start a server to read the app.
24+ await compileToString([config.elm], config.elmOptions).then(function (
25+ compiled_elm_code
26+ ) {
27+ // console.log(compiled_elm_code);
28+ const compiled = fs
29+ .readFileSync(config.template, "utf8")
30+ .replace(/~~_compiled_elm_code_~~/, () => compiled_elm_code)
31+ .replace(/~~_module_name_~~/, () => module_name);
32+
33+ fs.writeFileSync(config.target, compiled);
34+ });
35+}
36+
37+async function compile_to_string(config) {
38+ const elm_entry_module = fs.readFileSync(
39+ path.join(config.elmOptions.cwd, config.elm),
40+ "utf8"
41+ );
42+
43+ const module_name = elm_entry_module
44+ .split(/[\r\n]+/)[0]
45+ .match(/module ([A-Za-z0-9\.]+)/i)[1];
46+
47+ const compiled = await compileToString([config.elm], config.elmOptions).then(
48+ function (compiled_elm_code) {
49+ return fs
50+ .readFileSync(config.template, "utf8")
51+ .replace(/~~_module_name_~~/g, () => module_name)
52+ .replace(/~~_compiled_elm_code_~~/g, () => compiled_elm_code);
53+ }
54+ );
55+ return compiled;
56+}
57+
58+async function get_module_name(config) {
59+ const elm_entry_module = fs.readFileSync(
60+ path.join(config.cwd, config.elm),
61+ "utf8"
62+ );
63+
64+ const module_name = elm_entry_module
65+ .split(/[\r\n]+/)[0]
66+ .match(/module ([A-Za-z0-9\.]+)/i)[1];
67+ return module_name;
68+}
69+
70+async function create_runner(config) {
71+ const elm_entry_module = fs.readFileSync(config.elm, "utf8");
72+
73+ let module_name = elm_entry_module
74+ .split(/[\r\n]+/)[0]
75+ .match(/module ([A-Za-z0-9\.]+)/i)[1];
76+
77+ const module_name_sentence = module_name.replace(/([A-Z])/g, " $1");
78+
79+ const runner = fs
80+ .readFileSync(config.template, "utf8")
81+ .replace(/~~_module_name_~~/g, () => module_name)
82+ .replace(/~~_module_name_sentence_~~/g, () => module_name_sentence);
83+ fs.writeFileSync(config.target, runner);
84+}
85+
86+exports.compile_and_embed = compile_and_embed;
87+
88+exports.create_runner = create_runner;
89+
90+exports.compile_to_string = compile_to_string;
tests-rendering/automation/run.js+10−15
@@ -1,4 +1,3 @@
1−const compileToString = require("node-elm-compiler").compileToString;
2const { Builder, By, Key, until } = require("selenium-webdriver");
1const { Builder, By, Key, until } = require("selenium-webdriver");
3const chrome = require("selenium-webdriver/chrome");
2const chrome = require("selenium-webdriver/chrome");
4const firefox = require("selenium-webdriver/firefox");
3const firefox = require("selenium-webdriver/firefox");
@@ -7,6 +6,7 @@ const program = require("commander");
7const path = require("path");
6const path = require("path");
8const chalk = require("chalk");
7const chalk = require("chalk");
9const childProcess = require("child_process");
8const childProcess = require("child_process");
9+const compile_and_embed = require("./build.js").compile_and_embed;
10
10
11program
11program
12 .option("-s, --sauce", "run tests on sauce labs")
12 .option("-s, --sauce", "run tests on sauce labs")
@@ -17,6 +17,7 @@ program
17 .option("--build [value]", "Set build number for sauce labs")
17 .option("--build [value]", "Set build number for sauce labs")
18 .option("--name [value]", "Set run name for sauce labs")
18 .option("--name [value]", "Set run name for sauce labs")
19 .option("--verbose", "Print out all test results")
19 .option("--verbose", "Print out all test results")
20+ .option("--headless", "run tests without showing the browser")
20 .parse(process.argv);
21 .parse(process.argv);
21
22
22// 'Windows 10'
23// 'Windows 10'
@@ -102,17 +103,6 @@ function prepare_all_envs(config) {
102 return envs;
103 return envs;
103}
104}
104
105
105−async function compile_and_embed(config) {
106− var template = fs.readFileSync(config.template);
107− // we embed the compiled js to avoid having to start a server to read the app.
108− await compileToString(config.elm, config.elmOptions).then(function (
109− compiled_elm_code
110− ) {
111− const compiled = eval(`\`${template}\``);
112− fs.writeFileSync(config.target, compiled);
113− });
114−}
115−
116function prepare_sauce_driver(env) {
106function prepare_sauce_driver(env) {
117 const username = process.env.SAUCE_USERNAME;
107 const username = process.env.SAUCE_USERNAME;
118 const accessKey = process.env.SAUCE_ACCESS_KEY;
108 const accessKey = process.env.SAUCE_ACCESS_KEY;
@@ -137,8 +127,13 @@ function prepare_sauce_driver(env) {
137}
127}
138
128
139async function prepare_local_driver(env) {
129async function prepare_local_driver(env) {
140− const firefoxOptions = new firefox.Options().headless();
130+ const firefoxOptions = new firefox.Options();
141− const chromeOptions = new chrome.Options().headless();
131+ const chromeOptions = new chrome.Options();
132+
133+ if (program.headless) {
134+ firefoxOptions.headless();
135+ chromeOptions.headless();
136+ }
142
137
143 let driver = await new Builder()
138 let driver = await new Builder()
144 .forBrowser(env.browser)
139 .forBrowser(env.browser)
@@ -174,7 +169,7 @@ async function run_test(driver, url) {
174 await compile_and_embed({
169 await compile_and_embed({
175 template: "./tests-rendering/automation/templates/gather-styles.html",
170 template: "./tests-rendering/automation/templates/gather-styles.html",
176 target: "./tmp/test.html",
171 target: "./tmp/test.html",
177− elm: ["src/Tests/Run.elm"],
172+ elm: "src/Tests/All.elm",
178 elmOptions: { cwd: "./tests-rendering" },
173 elmOptions: { cwd: "./tests-rendering" },
179 });
174 });
180 console.log("Done compiling");
175 console.log("Done compiling");
tests-rendering/automation/templates/Run.elmnew file+14
@@ -0,0 +1,14 @@
1+module Tests.Run exposing (main)
2+
3+{-| _NOTE_ this is auto-generated! Notouchy!
4+-}
5+
6+import ~~_module_name_~~
7+import Testable.Runner
8+
9+
10+main : Testable.Runner.TestableProgram
11+main =
12+ Testable.Runner.program
13+ [ Testable.Runner.rename "~~_module_name_sentence_~~" ~~_module_name_~~.view
14+ ]
tests-rendering/automation/templates/gather-styles.html+147−69
@@ -2,22 +2,156 @@
2<html>
2<html>
3 <head>
3 <head>
4 <meta charset="UTF-8" />
4 <meta charset="UTF-8" />
5− <title>Rendering Benchmark Viewer</title>
5+ <title>Elm UI Rendering Test</title>
6 <script>
6 <script>
7− ${compiled_elm_code}
7+ ~~_compiled_elm_code_~~
8+ </script>
9+ <script>
10+ // Helpers
11+ // Calculations for canvas
12+ var PIXEL_RATIO = (function () {
13+ var ctx = document.createElement("canvas").getContext("2d"),
14+ dpr = window.devicePixelRatio || 1,
15+ bsr =
16+ ctx.webkitBackingStorePixelRatio ||
17+ ctx.mozBackingStorePixelRatio ||
18+ ctx.msBackingStorePixelRatio ||
19+ ctx.oBackingStorePixelRatio ||
20+ ctx.backingStorePixelRatio ||
21+ 1;
22+
23+ return dpr / bsr;
24+ })();
25+
26+ function createHiDPICanvas(w, h, id, ratio) {
27+ if (!ratio) {
28+ ratio = PIXEL_RATIO;
29+ }
30+ let can = document.getElementById(id);
31+ can.width = w * ratio;
32+ can.height = h * ratio;
33+ can.style.width = w + "px";
34+ can.style.height = h + "px";
35+ can.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0);
36+ return can;
37+ }
38+
39+ function isVisible(id, bbox) {
40+ var current = document.getElementById(id);
41+ var result = 0;
42+ if (current == document.elementFromPoint(bbox["left"], bbox["top"])) {
43+ result++;
44+ }
45+ if (
46+ current == document.elementFromPoint(bbox["left"], bbox["bottom"] - 1)
47+ ) {
48+ result++;
49+ }
50+ if (
51+ current == document.elementFromPoint(bbox["right"] - 1, bbox["top"])
52+ ) {
53+ result++;
54+ }
55+ if (
56+ current ==
57+ document.elementFromPoint(bbox["right"] - 1, bbox["bottom"] - 1)
58+ ) {
59+ result++;
60+ }
61+
62+ if (result == 4) {
63+ return true;
64+ } else {
65+ return false;
66+ }
67+ }
68+
69+ function getStyle(element) {
70+ var props = [];
71+ var style = window.getComputedStyle(element);
72+ for (var i = style.length; i--; ) {
73+ var name = style.item(i);
74+ var value = style.getPropertyValue(name);
75+ props.push([name, value]);
76+ }
77+ return props;
78+ }
79+
80+ function getBoundingBox(element) {
81+ var bbox = element.getBoundingClientRect();
82+ var style = window.getComputedStyle(element, null);
83+
84+ var padding = {
85+ top: parseFloat(style.getPropertyValue("padding-top")),
86+ bottom: parseFloat(style.getPropertyValue("padding-bottom")),
87+ left: parseFloat(style.getPropertyValue("padding-left")),
88+ right: parseFloat(style.getPropertyValue("padding-right")),
89+ };
90+
91+ return {
92+ top: bbox.top,
93+ bottom: bbox.bottom,
94+ left: bbox.left,
95+ right: bbox.right,
96+ width: bbox.width,
97+ height: bbox.height,
98+ padding: padding,
99+ };
100+ }
101+ function getTextMetrics(element) {
102+ // Given our element, we want to return the text metrics on the text within.
103+ // If it is an element we want to measure:
104+ // we want to get the font family
105+ // and the font size.
106+ // We're going to presume that the font is loaded.
107+ let childrenTextMetrics = [];
108+ for (i = 0; i < element.children.length; i++) {
109+ if (element.children[i].classList.contains("t")) {
110+ let style = window.getComputedStyle(element, null);
111+ let fontSize = style.getPropertyValue("font-size");
112+ let fontFamily = style.getPropertyValue("font-family");
113+ let ctx = canvas.getContext("2d");
114+
115+ ctx.font = fontSize + " " + fontFamily; //"16px Roboto";
116+ let text = ctx.measureText(element.children[i].innerText);
117+
118+ childrenTextMetrics.push({
119+ actualBoundingBoxAscent: text.actualBoundingBoxAscent,
120+ actualBoundingBoxDescent: text.actualBoundingBoxDescent,
121+ actualBoundingBoxLeft: text.actualBoundingBoxLeft,
122+ actualBoundingBoxRight: text.actualBoundingBoxRight,
123+ width: text.width,
124+ });
125+ }
126+ }
127+ return childrenTextMetrics;
128+ }
8 </script>
129 </script>
9 </head>
130 </head>
10 <style></style>
131 <style></style>
11− <body id="root"></body>
132+ <body id="root">
133+ <body id="root">
134+ <div id="elm-home"></div>
135+ <canvas id="canvas"></canvas>
136+ </body>
137+ </body>
12
138
13 <script type="text/javascript">
139 <script type="text/javascript">
140+ // Starting Elm App,
14− var app = Elm.Tests.Run.init();
141+ var app = Elm.~~_module_name_~~.init({
142+ node: document.getElementById("elm-home"),
143+ });
144+
145+ // create a canvas for text measurements
146+ let canvas = createHiDPICanvas(200, 100, "canvas");
15
147
16 var test_results = "waiting..";
148 var test_results = "waiting..";
17
149
18 app.ports.report.subscribe(function (results) {
150 app.ports.report.subscribe(function (results) {
19− // these are extracted by the script that runs the browser automation.
20 test_results = results;
151 test_results = results;
152+ // NOTE - this is the signal to the automation that it is cool to retrieve results now
153+ // So don't remove this like you did before :D
154+ document.title = "tests finished";
21 });
155 });
22
156
23 app.ports.analyze.subscribe(function (ids) {
157 app.ports.analyze.subscribe(function (ids) {
@@ -32,76 +166,20 @@
32 }
166 }
33 var style = getStyle(element);
167 var style = getStyle(element);
34 var bbox = getBoundingBox(element);
168 var bbox = getBoundingBox(element);
169+ var metrics = getTextMetrics(element);
35
170
36 var visible = isVisible(id, bbox);
171 var visible = isVisible(id, bbox);
37
172
173+ var result = {
174+ textMetrics: metrics,
175+ bbox: bbox,
176+ style: style,
177+ id: id,
38− var result = { bbox: bbox, style: style, id: id, isVisible: visible };
178+ isVisible: visible,
179+ };
39 results.push(result);
180 results.push(result);
40 }
181 }
41 app.ports.styles.send(results);
182 app.ports.styles.send(results);
42 });
183 });
43−
44− function isVisible(id, bbox) {
45− var current = document.getElementById(id);
46− var result = 0;
47− if (current == document.elementFromPoint(bbox["left"], bbox["top"])) {
48− result++;
49− }
50− if (
51− current == document.elementFromPoint(bbox["left"], bbox["bottom"] - 1)
52− ) {
53− result++;
54− }
55− if (
56− current == document.elementFromPoint(bbox["right"] - 1, bbox["top"])
57− ) {
58− result++;
59− }
60− if (
61− current ==
62− document.elementFromPoint(bbox["right"] - 1, bbox["bottom"] - 1)
63− ) {
64− result++;
65− }
66−
67− if (result == 4) {
68− return true;
69− } else {
70− return false;
71− }
72− }
73−
74− function getStyle(element) {
75− var props = [];
76− var style = window.getComputedStyle(element);
77− for (var i = style.length; i--; ) {
78− var name = style.item(i);
79− var value = style.getPropertyValue(name);
80− props.push([name, value]);
81− }
82− return props;
83− }
84−
85− function getBoundingBox(element) {
86− var bbox = element.getBoundingClientRect();
87− var style = window.getComputedStyle(element, null);
88−
89− var padding = {
90− top: parseFloat(style.getPropertyValue("padding-top")),
91− bottom: parseFloat(style.getPropertyValue("padding-bottom")),
92− left: parseFloat(style.getPropertyValue("padding-left")),
93− right: parseFloat(style.getPropertyValue("padding-right")),
94− };
95−
96− return {
97− top: bbox.top,
98− bottom: bbox.bottom,
99− left: bbox.left,
100− right: bbox.right,
101− width: bbox.width,
102− height: bbox.height,
103− padding: padding,
104− };
105− }
106 </script>
184 </script>
107</html>
185</html>
tests-rendering/automation/view.jsnew file+73
@@ -0,0 +1,73 @@
1+const fs = require("fs");
2+const program = require("commander");
3+const path = require("path");
4+const chalk = require("chalk");
5+const childProcess = require("child_process");
6+const build = require("./build.js");
7+const chokidar = require("chokidar");
8+const http = require("http");
9+
10+var filepath = null;
11+var test_filepath = null;
12+program
13+ .option("--all", "run all the tests")
14+ .option("--debug", "run with debug on")
15+ .arguments("<filepath>")
16+ .action(function (p) {
17+ test_filepath = path.join("./tests-rendering/cases/open", p);
18+ })
19+ .parse(process.argv);
20+
21+(async () => {
22+ if (test_filepath && test_filepath == null && !program.run) {
23+ console.log("Open Cases");
24+ console.log("");
25+ fs.readdirSync("./tests-rendering/cases/open").forEach((file) => {
26+ if (file.endsWith("elm")) {
27+ console.log(" " + file);
28+ }
29+ });
30+ console.log("");
31+ return;
32+ }
33+
34+ if (program.all) {
35+ filepath = "./src/Tests/All.elm";
36+ } else {
37+ filepath = "src/Tests/Run.elm";
38+ build.create_runner({
39+ elm: test_filepath,
40+ template: "./tests-rendering/automation/templates/Run.elm",
41+ target: "./tests-rendering/src/Tests/Run.elm",
42+ });
43+ }
44+
45+ //
46+ // Compile and serve
47+
48+ let content = await build.compile_to_string({
49+ template: "./tests-rendering/automation/templates/gather-styles.html",
50+ elm: filepath,
51+ elmOptions: { cwd: "./tests-rendering", debug: program.debug },
52+ });
53+
54+ console.log("Finished compiling");
55+ // console.log(content);
56+
57+ chokidar.watch("./tests-rendering/*.elm").on("all", (event, path) => {
58+ console.log("Changes detected, refresh!");
59+ content = build.compile_to_string({
60+ template: "./tests-rendering/automation/templates/gather-styles.html",
61+ elm: filepath,
62+ elmOptions: { cwd: "./tests-rendering", debug: program.debug },
63+ });
64+ });
65+ console.log("Serving on http://localhost:8080");
66+ http
67+ .createServer(function (req, res) {
68+ res.writeHead(200, { "Content-Type": "text/html" });
69+ res.write(content);
70+ res.end();
71+ })
72+ .listen(8080);
73+})();
tests-rendering/cases/open/InFrontSize.elm+2−2
@@ -1,4 +1,4 @@
1−module InFrontSize exposing (main)
1+module InFrontSize exposing (view)
2
2
3{-|
3{-|
4
4
@@ -16,7 +16,7 @@ import Testable.Element.Background as Background
16import Testable.Element.Border as Border
16import Testable.Element.Border as Border
17
17
18
18
19−main =
19+view =
20 layout []
20 layout []
21 (el
21 (el
22 [ width (px 100)
22 [ width (px 100)
tests-rendering/cases/open/LabelledInputAlignRight.elmnew file+28
@@ -0,0 +1,28 @@
1+module LabelledInputAlignRight exposing (view)
2+
3+import Testable.Element exposing (..)
4+import Testable.Element.Input as Input
5+
6+
7+view =
8+ layout [] <|
9+ column [ width fill ]
10+ [ Input.text
11+ [ width (px 200)
12+ , alignRight
13+ ]
14+ { onChange = always False
15+ , text = ""
16+ , placeholder = Nothing
17+ , label = Input.labelLeft [] (text "label")
18+ }
19+ , Input.text
20+ [ width (px 200)
21+ , alignRight
22+ ]
23+ { onChange = always False
24+ , text = ""
25+ , placeholder = Nothing
26+ , label = Input.labelHidden "label"
27+ }
28+ ]
tests-rendering/cases/open/NearbyElementBordersOverlap.elmnew file+46
@@ -0,0 +1,46 @@
1+module NearbyElementBordersOverlap exposing (view)
2+
3+{-| Elements placed with onLeft, onRight, above & below overlap main element's border
4+
5+
6+# inFront elements with width fill are contained within the parent's border
7+
8+<https://github.com/mdgriffith/elm-ui/issues/223>
9+
10+In addition to the overlap, it affects layout in unexpected ways: eg if the elements
11+are the same height, onLeft and onRight elements will be vertically offset
12+from the main element.
13+
14+-}
15+
16+import Testable.Element exposing (..)
17+import Testable.Element.Border as Border
18+
19+
20+blue =
21+ rgb 0 0 1
22+
23+
24+green =
25+ rgb 0 1 0
26+
27+
28+grey =
29+ rgb 0.5 0.5 0.5
30+
31+
32+view =
33+ layout [ width fill, height fill ] <|
34+ el
35+ [ centerX
36+ , centerY
37+ , Border.width 10
38+ , Border.color green
39+ , padding 50
40+ , above <| el [ Border.color grey, Border.width 10 ] <| text "above"
41+ , below <| el [ Border.color grey, Border.width 10 ] <| text "below"
42+ , onRight <| el [ Border.color blue, Border.width 10 ] <| text "onRight"
43+ , onLeft <| el [ Border.color blue, Border.width 10 ] <| text "onLeft"
44+ ]
45+ <|
46+ text "Centre"
tests-rendering/cases/open/Scrollbar2.elm+1−1
@@ -1,4 +1,4 @@
1−module Main exposing (main, myElement, sidebar)
1+module Scrollbar2 exposing (main, myElement, sidebar)
2
2
3import Element exposing (Element, alignRight, centerY, column, el, fill, height, padding, px, rgb255, row, spacing, text, width)
3import Element exposing (Element, alignRight, centerY, column, el, fill, height, padding, px, rgb255, row, spacing, text, width)
4import Element.Background as Background
4import Element.Background as Background
tests-rendering/cases/open/Scrollbars.elm+1−1
@@ -1,4 +1,4 @@
1−module Main exposing (main)
1+module Scrollbars exposing (main)
2
2
3import Element exposing (..)
3import Element exposing (..)
4import Element.Background as Background
4import Element.Background as Background
tests-rendering/cases/open/StackedScrollingColumnsHeight.elmnew file+42
@@ -0,0 +1,42 @@
1+module StackedScrollingColumnsHeight exposing (..)
2+
3+{-|
4+
5+
6+# Column height can be set incorrectly for two stacked columns with scrollbarY
7+
8+<https://github.com/mdgriffith/elm-ui/issues/197>
9+
10+Both red and green columns should always have equal height.
11+
12+Currently, the height is set incorrectly if only one column has enough content to scroll.
13+
14+Both columns are correctly set to the same height only if neither has enough content
15+to scroll or if both have enough content to scroll.
16+
17+-}
18+
19+import Testable.Element exposing (..)
20+import Testable.Element.Background as Background
21+
22+
23+view =
24+ layout [ height fill ] <|
25+ column [ height fill ]
26+ [ column
27+ [ height fill
28+ , scrollbarY
29+ , Background.color (rgb 0 255 0)
30+ ]
31+ <|
32+ List.map (\_ -> text "Hello") <|
33+ List.range 1 20
34+ , column
35+ [ height fill
36+ , scrollbarY
37+ , Background.color (rgb 255 0 0)
38+ ]
39+ <|
40+ List.map (\_ -> text "Hello") <|
41+ List.range 1 3
42+ ]
tests-rendering/cases/open/WeirdCentering.elm+2−4
@@ -1,13 +1,11 @@
1−module WeirdCentering exposing (main)
1+module WeirdCentering exposing (view)
2
2
3−import Html exposing (Html)
4import Testable.Element exposing (..)
3import Testable.Element exposing (..)
5import Testable.Element.Background as Background
4import Testable.Element.Background as Background
6
5
7
6
8−main =
7+view =
9 layout [] <|
8 layout [] <|
10− -- row [] [ el [] (text "Example with centerX:") ]
11 column []
9 column []
12 [ text "Example with centerX:"
10 [ text "Example with centerX:"
13 , row
11 , row
tests-rendering/cases/resolved/ClippedElInFixedWidthColumn.elmnew file+31
@@ -0,0 +1,31 @@
1+module ClippedElInFixedWidthColumn exposing (..)
2+
3+{-| el [ clip ] inside a fixed-width column rendered with 0px height in Chrome & Firefox
4+
5+<https://github.com/mdgriffith/elm-ui/issues/191>
6+
7+If an el [ clip ] is placed inside a fixed-width column which is inside a layout
8+with [ width fill, height fill ], then the element is rendered with 0px height in Chrome:
9+
10+layout [ width fill, height fill ] <|
11+column [ width <| px 300 ][ el [ clip ] <| text "The quick brown fox" ]
12+
13+In Firefox, the element is initially rendered correctly, but is resized to 0px height
14+on viewport resize. In Safari, the element is displayed correctly.
15+
16+The above seems to be the minimal reproduction:
17+
18+Removing attributes from layout or from column or from el makes the issue disappear.
19+Replacing column [ width <| px 300 ] with column [ width fill ] makes the issue disappear.
20+Replacing column with el also makes the issue disappear.
21+Adding htmlAttribute <| Attr.style "flex-basis" "auto" to clipped el is a workaround.
22+
23+-}
24+
25+import Testable.Element exposing (..)
26+
27+
28+view =
29+ layout [ width fill, height fill ] <|
30+ column [ width <| px 300 ]
31+ [ el [ clip ] <| text "The quick brown fox" ]
tests-rendering/cases/resolved/ElInFixedHeightColumn.elmnew file+41
@@ -0,0 +1,41 @@
1+module ElInFixedHeightColumn exposing (view)
2+
3+{-| el inside a fixed height column is rendered with zero height in Safari
4+
5+<https://github.com/mdgriffith/elm-ui/issues/190>
6+
7+If I put an el into a column of fixed height, the el is rendered with zero height
8+in Safari:
9+
10+ layout [] <|
11+ column
12+ [ width fill
13+ , height <| px 200
14+ ]
15+ [ el [ Border.width 3, Border.color <| rgb255 0 0 0 ] <| text "an element" ]
16+
17+Adding htmlAttribute <| Attr.style "flex-basis" "auto" to the el is a workaround
18+that fixes the problem in this instance.
19+
20+Expected behavior
21+
22+Element should be rendered the same as in Firefox & Chrome, with the border going
23+around the text.
24+
25+-}
26+
27+import Testable.Element exposing (..)
28+import Testable.Element.Border as Border
29+
30+
31+view =
32+ layout [] <|
33+ column
34+ [ width fill
35+ , height <| px 200
36+ ]
37+ [ el
38+ []
39+ <|
40+ text "an element"
41+ ]
tests-rendering/cases/resolved/Images/ImageRegression.elmnew file+63
@@ -0,0 +1,63 @@
1+module ImageRegression exposing (main)
2+
3+{-| <https://github.com/mdgriffith/elm-ui/issues/232>
4+-}
5+
6+import Browser
7+import Element exposing (Element, centerX, clipX, el, image, px, rgb255, row, shrink, width)
8+import Element.Background as Background
9+import Html exposing (Html, button, div, text)
10+import Html.Events exposing (onClick)
11+
12+
13+type alias Model =
14+ Int
15+
16+
17+type Msg
18+ = NoOp
19+
20+
21+update : Msg -> Model -> Model
22+update msg model =
23+ model
24+
25+
26+view : Model -> Html Msg
27+view model =
28+ Element.layout [] <|
29+ row
30+ [ centerX
31+ , width shrink
32+ , Background.color <| rgb255 255 255 255
33+ ]
34+ [ viewCard "qs" True
35+ , viewCard "ah" False
36+ ]
37+
38+
39+main : Program () Model Msg
40+main =
41+ Browser.sandbox
42+ { init = 0
43+ , view = view
44+ , update = update
45+ }
46+
47+
48+viewCard : String -> Bool -> Element Msg
49+viewCard card bool =
50+ let
51+ source =
52+ "https://hearts-bawolk.herokuapp.com/static/cards/" ++ card ++ ".png"
53+
54+ overlapStyles =
55+ if bool then
56+ [ width (px 50)
57+ , clipX
58+ ]
59+
60+ else
61+ []
62+ in
63+ el overlapStyles (image [] { src = source, description = "" })
tests-rendering/cases/resolved/Images/ImageRegression2.elmnew file+19
@@ -0,0 +1,19 @@
1+module ImageRegression2 exposing (main)
2+
3+{-| <https://github.com/mdgriffith/elm-ui/issues/228>
4+-}
5+
6+import Element exposing (..)
7+
8+
9+main =
10+ Element.layout []
11+ (Element.row [ width fill, height fill, explain Debug.todo ]
12+ [ text "BEFORE"
13+ , image []
14+ { src = "https://placekitten.com/300/200"
15+ , description = "kitten"
16+ }
17+ , text "AFTER"
18+ ]
19+ )
tests-rendering/cases/resolved/Images/ImageSizing.elmnew file+24
@@ -0,0 +1,24 @@
1+module ImageSizing exposing (main)
2+
3+{-| <https://github.com/mdgriffith/elm-ui/issues/62>
4+-}
5+
6+import Element as E exposing (column, el, px, row, text)
7+import Element.Border as Border
8+import Element.Font as Font
9+import Html exposing (Html)
10+
11+
12+main : Html ()
13+main =
14+ E.layout [ E.height E.fill, Border.width 5, E.explain Debug.todo ] <|
15+ E.image
16+ [ -- E.height (E.px 500)
17+ -- ,
18+ -- E.width E.fill
19+ E.height E.fill
20+ ]
21+ -- <| px 500 ]
22+ { src = "http://bburdette.github.io/music-reader.png"
23+ , description = "music-reader screenshot"
24+ }
tests-rendering/cases/resolved/Input/FocusLinks.elmnew file+37
@@ -0,0 +1,37 @@
1+module FocusLinks exposing (main)
2+
3+import Element exposing (Color, Element, el, focused, layout, link, row, spacing, text)
4+import Element.Border as Border
5+import Element.Region as Region
6+import Html exposing (Html)
7+
8+
9+main : Html msg
10+main =
11+ layout [] links
12+
13+
14+links : Element msg
15+links =
16+ row [ spacing 10 ]
17+ [ siteLink "Elm website" "https://elm-lang.org/"
18+ , siteLink "Elm-ui" "https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/Element"
19+ ]
20+
21+
22+siteLink : String -> String -> Element msg
23+siteLink label url =
24+ link [ focused [ Border.glow blue 2 ] ]
25+ { url = url
26+ , label = text label
27+ }
28+
29+
30+blue : Color
31+blue =
32+ Element.fromRgb255
33+ { red = 100
34+ , green = 180
35+ , blue = 250
36+ , alpha = 1
37+ }
tests-rendering/cases/open/FocusStylePrecedingElements.elm → tests-rendering/cases/resolved/Input/FocusStylePrecedingElements.elmrenamed+3−3
@@ -22,9 +22,9 @@ Disabling it produces the correct focus behaviour.
22
22
23-}
23-}
24
24
25−import Testable.Element exposing (..)
25+import Element exposing (..)
26−import Testable.Element.Font as Font
26+import Element.Font as Font
27−import Testable.Element.Input as Input
27+import Element.Input as Input
28
28
29
29
30main =
30main =
tests-rendering/cases/resolved/Input/InputAlignment.elmnew file+44
@@ -0,0 +1,44 @@
1+module InputAlignment exposing (main)
2+
3+import Browser
4+import Element exposing (fill, padding, width)
5+import Element.Border as Border
6+import Element.Font as Font
7+import Element.Input as Input
8+import Html exposing (Html)
9+
10+
11+view : () -> Html ()
12+view () =
13+ Element.layout [ Font.alignRight ] <|
14+ Element.column [ padding 10 ]
15+ [ Element.el [ Border.width 1, padding 5, width fill ] <| Element.text "Element.el"
16+ , Input.text
17+ [ Border.width 1
18+ , padding 5
19+ , width fill
20+ , Border.rounded 0
21+ , Font.color (Element.rgb 0 0.5 0.5)
22+ ]
23+ { onChange = always ()
24+ , text = "Input.text"
25+ , placeholder = Nothing
26+ , label = Input.labelHidden "Input.text"
27+ }
28+ , Element.paragraph []
29+ [ Element.text "Helooooo!" ]
30+ , Element.row []
31+ [ Element.text "one!"
32+ , Element.text "two!"
33+ , Element.text "three!"
34+ ]
35+ ]
36+
37+
38+main : Program () () ()
39+main =
40+ Browser.sandbox
41+ { init = ()
42+ , view = view
43+ , update = \_ _ -> ()
44+ }
tests-rendering/cases/resolved/Input/LabelAlignBaseline.elmnew file+34
@@ -0,0 +1,34 @@
1+module LabelAlignBaseline exposing (..)
2+
3+import Element exposing (Element, alignRight, centerY, el, fill, padding, rgb255, row, spacing, text, width)
4+import Element.Background as Background
5+import Element.Border as Border
6+import Element.Font as Font
7+import Element.Input as Input
8+
9+
10+type Msg
11+ = Msg
12+
13+
14+main =
15+ Element.layout [] <|
16+ Element.column []
17+ [ Element.row []
18+ [ Element.text "dissociated label"
19+ , Input.text []
20+ { text = "input"
21+ , label = Input.labelHidden "hidden"
22+ , onChange = \_ -> Msg
23+ , placeholder = Nothing
24+ }
25+ ]
26+ , Element.row []
27+ [ Input.text []
28+ { text = "input"
29+ , label = Input.labelLeft [] <| Element.text "associated label"
30+ , onChange = \_ -> Msg
31+ , placeholder = Nothing
32+ }
33+ ]
34+ ]
tests-rendering/cases/resolved/Input/Placeholder.elmnew file+59
@@ -0,0 +1,59 @@
1+module Placeholder exposing (main)
2+
3+import Element exposing (..)
4+import Element.Background as Background
5+import Element.Input as Input
6+import Element.Keyed as Keyed
7+import Html.Attributes exposing (style)
8+
9+
10+grey =
11+ rgb 0.8 0.8 0.8
12+
13+
14+darkGrey =
15+ rgb 0.7 0.7 0.7
16+
17+
18+type Msg
19+ = NoMsg String
20+
21+
22+main =
23+ Element.layout [ width fill, height fill ] <|
24+ column
25+ [ width fill
26+ , inFront
27+ (el
28+ [ width fill
29+ , Background.color grey
30+ , padding 20
31+ , below <|
32+ el
33+ [ height (px 300)
34+ , width (px 300)
35+ , Background.color darkGrey
36+ , htmlAttribute <| style "z-index" "1"
37+ , moveRight 50
38+ , padding 50
39+ , alpha 0.5
40+ ]
41+ (el [ alignBottom ] (text "I'm a dropdown menu."))
42+ ]
43+ (text "I'm a toolbar.")
44+ )
45+ ]
46+ [ Input.text []
47+ { onChange = NoMsg
48+ , text = ""
49+ , placeholder = Just (Input.placeholder [] (text "I'm a text input."))
50+ , label = Input.labelAbove [] none
51+ }
52+ , Input.multiline []
53+ { onChange = NoMsg
54+ , text = ""
55+ , placeholder = Just (Input.placeholder [] (text "I'm a multiline input."))
56+ , label = Input.labelAbove [] none
57+ , spellcheck = False
58+ }
59+ ]
tests-rendering/cases/resolved/Input/Slider.elmnew file+74
@@ -0,0 +1,74 @@
1+module Slider exposing (main)
2+
3+import Browser
4+import Element as Element exposing (Element)
5+import Element.Background as Background
6+import Element.Input as Input
7+import Html exposing (Html, button, div, text)
8+import Html.Events exposing (onClick)
9+
10+
11+type alias Model =
12+ { rangeValue : Float }
13+
14+
15+initialModel : Model
16+initialModel =
17+ { rangeValue = 160.0 }
18+
19+
20+type Msg
21+ = UpdateRange Float
22+
23+
24+update : Msg -> Model -> Model
25+update msg model =
26+ case msg of
27+ UpdateRange value ->
28+ { model | rangeValue = value }
29+
30+
31+viewModal =
32+ Element.el
33+ [ Element.width Element.fill
34+ , Element.height Element.fill
35+ , Element.paddingEach { top = 100, left = 0, bottom = 0, right = 0 }
36+ , Background.color <| Element.rgba 0 0 0 0.8
37+ ]
38+ (Element.el [] (Element.text "Hello Modal"))
39+
40+
41+view : Model -> Html Msg
42+view model =
43+ Element.layout
44+ [--Element.inFront viewModal
45+ ]
46+ <|
47+ Input.slider
48+ [ Element.width Element.fill
49+ , Element.behindContent <|
50+ Element.el
51+ [ Element.width Element.fill
52+ , Element.height (Element.px 2)
53+ , Element.centerY
54+ , Background.color (Element.rgb 0.5 0.5 0.5)
55+ ]
56+ Element.none
57+ ]
58+ { onChange = UpdateRange
59+ , label = Input.labelHidden ""
60+ , min = 60.0
61+ , max = 280.0
62+ , value = model.rangeValue
63+ , thumb = Input.defaultThumb
64+ , step = Just 1.0
65+ }
66+
67+
68+main : Program () Model Msg
69+main =
70+ Browser.sandbox
71+ { init = initialModel
72+ , view = view
73+ , update = update
74+ }
tests-rendering/cases/resolved/Layout/BreaksWithinParagraph.elmnew file+17
@@ -0,0 +1,17 @@
1+module BreaksWithinParagraph exposing (main)
2+
3+import Browser
4+import Element exposing (..)
5+import Element.Background as Background
6+import Element.Border as Border
7+import Element.Font as Font
8+
9+
10+main =
11+ layout [ width fill, height fill ] <|
12+ paragraph [ Border.width 1, width (px 50) ]
13+ [ row []
14+ [ text "Thequick"
15+ ]
16+ , text "redfox"
17+ ]
tests-rendering/cases/resolved/Layout/ColumnLayouts.elmnew file+103
@@ -0,0 +1,103 @@
1+module ColumnLayouts exposing (main)
2+
3+{-| -}
4+
5+import Element exposing (..)
6+import Element.Background as Background
7+import Element.Border as Border
8+import Element.Font as Font
9+
10+
11+main =
12+ layout [] <|
13+ column [ spacing 48 ]
14+ [ column
15+ [ width fill
16+ , height <| px 200
17+ , spacing 24
18+ , Border.width 1
19+ , Border.color pink
20+ ]
21+ [ elem
22+ , elem
23+ , elem
24+ ]
25+ , column
26+ [ width fill
27+ , spacing 24
28+ , Border.width 1
29+ , Border.color pink
30+ ]
31+ [ elem
32+ , elem
33+ , elem
34+ ]
35+ , el [ height <| px 400 ] <|
36+ column [ height fill ]
37+ [ column
38+ [ width fill
39+ , height <| px 200
40+ , spacing 24
41+ , Border.width 1
42+ , Border.color pink
43+ ]
44+ [ elem
45+ , elem
46+ , el [ alignBottom ] elem
47+ ]
48+ , el [ alignBottom ] elem
49+ ]
50+ , column
51+ [ width fill
52+ , height <| px 200
53+ , spacing 24
54+ , Border.width 1
55+ , Border.color pink
56+ ]
57+ [ elem
58+ , el [] box
59+ , el [ alignBottom ] elem
60+ ]
61+ , column
62+ [ width fill
63+ , height <| px 200
64+ , spacing 24
65+ , Border.width 1
66+ , Border.color pink
67+ ]
68+ [ elem
69+ , el [] box
70+ , filled
71+ , el [ alignBottom ] elem
72+ ]
73+ ]
74+
75+
76+filled =
77+ el
78+ [ width fill
79+ , height fill
80+ , Background.color pink
81+ ]
82+ (text "an element")
83+
84+
85+elem =
86+ el
87+ [ Background.color pink
88+ ]
89+ (text "an element")
90+
91+
92+box =
93+ el
94+ [ width (px 50)
95+ , height (px 50)
96+ , Background.color (rgb (240 / 255) 0 (245 / 255))
97+ , Font.color (rgb 1 1 1)
98+ ]
99+ none
100+
101+
102+pink =
103+ rgb (240 / 255) 0 (245 / 255)
tests-rendering/cases/resolved/Layout/Columns/DistributeHeight.elmnew file+46
@@ -0,0 +1,46 @@
1+module DistributeHeight exposing (main)
2+
3+import Browser
4+import Element exposing (column, el, fill, fillPortion, height, minimum, none, px, rgb, row, text, width)
5+import Element.Background as Bg
6+import Html as Html exposing (Html)
7+
8+
9+type alias Model =
10+ ()
11+
12+
13+update : msg -> Model -> Model
14+update _ model =
15+ model
16+
17+
18+view : model -> Html msg
19+view _ =
20+ Element.layout [ height fill, width fill ] <|
21+ column [ height fill, width fill ]
22+ [ row
23+ [ height
24+ fill
25+ , width fill
26+ , Bg.color <| rgb 1 0 0
27+ ]
28+ [ el
29+ [ height <| px 200
30+ , width fill
31+ , Bg.color <| rgb 1 0 1
32+ ]
33+ (text "Helloooo!")
34+ ]
35+ , row [ height fill, width fill, Bg.color <| rgb 0 1 0 ]
36+ [ none ]
37+ ]
38+
39+
40+main : Program () Model msg
41+main =
42+ Browser.sandbox
43+ { init = ()
44+ , view = view
45+ , update = update
46+ }
tests-rendering/cases/resolved/Layout/Columns/DistributeHeightCorrectly2.elmnew file+86
@@ -0,0 +1,86 @@
1+module Other exposing (main)
2+
3+import Browser
4+import Element exposing (..)
5+import Element.Border as Border
6+import Element.Events as Events
7+import Html exposing (Html)
8+import Html.Attributes
9+
10+
11+type alias Model =
12+ { count : Int }
13+
14+
15+initialModel : Model
16+initialModel =
17+ { count = 0 }
18+
19+
20+type Msg
21+ = Increment
22+ | Decrement
23+
24+
25+update : Msg -> Model -> Model
26+update msg model =
27+ case msg of
28+ Increment ->
29+ { model | count = model.count + 1 }
30+
31+ Decrement ->
32+ { model | count = model.count - 1 }
33+
34+
35+view : Model -> Html Msg
36+view model =
37+ viewElements model
38+ |> layout []
39+
40+
41+viewElements : Model -> Element Msg
42+viewElements model =
43+ el [ height fill ] <|
44+ column [ height fill ]
45+ [ el
46+ [ height (fillPortion 1)
47+ ]
48+ <|
49+ viewCounter model
50+ , el
51+ [ height (fillPortion 2)
52+ ]
53+ <|
54+ viewCounters model
55+ ]
56+
57+
58+flexBasisZero : Element.Attribute msg
59+flexBasisZero =
60+ htmlAttribute (Html.Attributes.style "flex-basis" "0")
61+
62+
63+viewCounters : Model -> Element Msg
64+viewCounters model =
65+ column [ height fill ]
66+ (List.repeat model.count model
67+ |> List.map viewCounter
68+ )
69+
70+
71+viewCounter : Model -> Element Msg
72+viewCounter model =
73+ column [ width fill, height fill, Border.width 1, Border.dotted ]
74+ [ el [ Events.onClick Increment, Border.width 1, Border.rounded 3 ] <| text "+1"
75+ , el [] <| text <| String.fromInt model.count
76+ , el [ Events.onClick Decrement, Border.width 1, Border.rounded 3 ] <| text "-1"
77+ ]
78+
79+
80+main : Program () Model Msg
81+main =
82+ Browser.sandbox
83+ { init = initialModel
84+ , view = view
85+ , update = update
86+ }
tests-rendering/cases/open/SafariBugIssue147.elm → tests-rendering/cases/resolved/Layout/Columns/DoNotCollapseBelow0.elmrenamed+13−3
@@ -1,4 +1,4 @@
1−module SafariBugIssue147 exposing (main)
1+module DoNotCollapseBelow0 exposing (main)
2
2
3{-|
3{-|
4
4
@@ -25,14 +25,24 @@ I was able to pinpoint the issue using git bisect to this fd08f1a commit, which
25-}
25-}
26
26
27import Browser
27import Browser
28+import Element exposing (column, el, fill, height, layout, scrollbarY, text)
28import Html exposing (Html)
29import Html exposing (Html)
29−import Testable.Element exposing (..)
30
30
31
31
32−main =
32+view : () -> Html ()
33+view () =
33 layout [ height fill ] <|
34 layout [ height fill ] <|
34 column
35 column
35 [ height fill ]
36 [ height fill ]
36 [ el [] <| text "Element that Safari gives height 0, if inside an el and not just text."
37 [ el [] <| text "Element that Safari gives height 0, if inside an el and not just text."
37 , text "Text below the el above"
38 , text "Text below the el above"
38 ]
39 ]
40+
41+
42+main : Program () () ()
43+main =
44+ Browser.sandbox
45+ { init = ()
46+ , view = view
47+ , update = \() () -> ()
48+ }
tests-rendering/cases/resolved/Layout/Columns/SafariTwo.elmnew file+40
@@ -0,0 +1,40 @@
1+module SafariTwo exposing (main)
2+
3+{-| el inside a fixed height column is rendered with zero height in Safari
4+
5+<https://github.com/mdgriffith/elm-ui/issues/190>
6+
7+If I put an el into a column of fixed height, the el is rendered with zero height
8+in Safari:
9+
10+ layout [] <|
11+ column
12+ [ width fill
13+ , height <| px 200
14+ ]
15+ [ el [ Border.width 3, Border.color <| rgb255 0 0 0 ] <| text "an element" ]
16+
17+Adding htmlAttribute <| Attr.style "flex-basis" "auto" to the el is a workaround
18+that fixes the problem in this instance.
19+
20+Expected behavior
21+
22+Element should be rendered the same as in Firefox & Chrome, with the border going
23+around the text.
24+
25+-}
26+
27+import Element exposing (..)
28+
29+
30+main =
31+ layout [] <|
32+ column
33+ [ width fill
34+ , height <| px 200
35+ ]
36+ [ el
37+ []
38+ <|
39+ text "an element"
40+ ]
tests-rendering/cases/resolved/Layout/NestedParagraphs.elmnew file+165
@@ -0,0 +1,165 @@
1+module Layout.NestedParagraphs exposing (view)
2+
3+{-| Paragraph with children more than one level deep breaks flow
4+
5+<https://github.com/mdgriffith/elm-ui/issues/173>
6+
7+First of all, thanks for such a pleasant library to use! It's been awesome not having to use CSS.
8+
9+The problem I ran into is that paragraph only seems correctly flow text in children a single level deep. As an example, I made an Ellie demonstrating this with an el within a link within a paragraph:
10+
11+<https://ellie-app.com/7JcgLRNprF7a1>
12+
13+This might be a regression, as the resolved #50 and #103 seem to refer to the same problem.
14+
15+Expected behavior
16+Text should flow with no breaks in the paragraph.
17+
18+Versions
19+
20+ OS: macOS
21+ Browser: Firefox
22+ Browser Version: 71.0
23+ Elm Version: 0.19.1
24+ Elm UI Version: 1.1.5
25+
26+-}
27+
28+import Testable.Element as Element exposing (..)
29+import Testable.Element.Font as Font
30+import Testable.Generator
31+
32+
33+view =
34+ layout [] <|
35+ column [ spacing 48 ]
36+ [ paragraph []
37+ [ text "This is a paragraph with a "
38+ , el [ Font.bold ] <| text "child"
39+ , text " of depth one."
40+ ]
41+ , paragraph []
42+ [ text "This is a paragraph with a "
43+ , link []
44+ { label =
45+ el [ Font.bold ]
46+ (text Testable.Generator.lorem)
47+ , url = "http://example.com"
48+ }
49+ , text " of depth two."
50+ ]
51+ , el [ Font.size 32 ] (text "Many nested els")
52+ , paragraph []
53+ [ text "This is a paragraph with a "
54+ , link []
55+ { label =
56+ el [ Font.bold ]
57+ (text Testable.Generator.lorem)
58+ , url = "http://example.com"
59+ }
60+ , text " of depth two."
61+ , el [] (el [] (el [] (text Testable.Generator.lorem)))
62+ , el [] (el [] (el [] (el [] (text Testable.Generator.lorem))))
63+ ]
64+ , el [ Font.size 32 ] (text "NestedParas in els")
65+ , paragraph []
66+ [ text "This is a paragraph with a "
67+ , link []
68+ { label =
69+ el [ Font.bold ]
70+ (text Testable.Generator.lorem)
71+ , url = "http://example.com"
72+ }
73+ , text " of depth two."
74+ , el [] (el [] (el [] (text Testable.Generator.lorem)))
75+ , el []
76+ (paragraph []
77+ [ el []
78+ (el [] (text Testable.Generator.lorem))
79+ ]
80+ )
81+ ]
82+ , el [ Font.size 32 ] (text "Nested with link")
83+ , paragraph []
84+ [ text "This is a paragraph with a "
85+ , link []
86+ { label =
87+ el [ Font.bold ] <|
88+ text "child"
89+ , url = "http://example.com"
90+ }
91+ , text " of depth two."
92+ ]
93+ , el [ Font.size 32 ] (text "Para with boxes")
94+ , paragraph []
95+ [ text Testable.Generator.short
96+ , Testable.Generator.box
97+ , text Testable.Generator.short
98+
99+ -- , text Testable.Generator.lorem
100+ , Testable.Generator.box
101+ ]
102+ , el [ Font.size 32 ] (text "Row with boxes")
103+ , paragraph []
104+ [ text Testable.Generator.short
105+ , row [ spacing 25 ]
106+ [ Testable.Generator.box
107+ , text Testable.Generator.short
108+ , Testable.Generator.box
109+
110+ -- , text Testable.Generator.lorem
111+ ]
112+ , text Testable.Generator.short
113+
114+ -- , text Testable.Generator.lorem
115+ , Testable.Generator.box
116+ , paragraph []
117+ [ text "This is a paragraph with a "
118+ , el [ Font.bold ] <| text "child"
119+ , text " of depth one."
120+ ]
121+ ]
122+ , el [ Font.size 32 ] (text "Row with boxes and lots of content")
123+ , paragraph []
124+ [ column [ alignLeft ]
125+ [ Testable.Generator.box, Testable.Generator.box, Testable.Generator.box ]
126+ , text Testable.Generator.short
127+ , row [ spacing 25 ]
128+ [ Testable.Generator.box
129+ , text Testable.Generator.lorem
130+ , Testable.Generator.box
131+
132+ -- , text Testable.Generator.lorem
133+ ]
134+ , text Testable.Generator.short
135+
136+ -- , text Testable.Generator.lorem
137+ , Testable.Generator.box
138+ , paragraph []
139+ [ text "This is a paragraph with a "
140+ , el [ Font.bold ] <| text "child"
141+ , text " of depth one."
142+ ]
143+ ]
144+ , el [ Font.size 32 ] (text "Row with boxes")
145+ , paragraph []
146+ [ text Testable.Generator.short
147+ , row []
148+ [ Testable.Generator.box
149+
150+ -- , text Testable.Generator.lorem
151+ , Testable.Generator.box
152+
153+ -- , text Testable.Generator.lorem
154+ ]
155+ , text Testable.Generator.short
156+
157+ -- , text Testable.Generator.lorem
158+ , Testable.Generator.box
159+ , paragraph []
160+ [ text "This is a paragraph with a "
161+ , el [ Font.bold ] <| text "child"
162+ , text " of depth one."
163+ ]
164+ ]
165+ ]
tests-rendering/cases/resolved/Layout/Rounded.elmnew file+54
@@ -0,0 +1,54 @@
1+module Rounded exposing (main)
2+
3+import Element exposing (..)
4+import Element.Background as Background
5+import Html exposing (Html)
6+
7+
8+sizePadding =
9+ 10
10+
11+
12+sizeSpacing =
13+ 11
14+
15+
16+nbElement =
17+ 10
18+
19+
20+sizeElement =
21+ 50
22+
23+
24+totalSizeElement =
25+ nbElement * sizeElement
26+
27+
28+totalSpacing =
29+ (nbElement - 1) * sizeSpacing
30+
31+
32+totalPadding =
33+ 2 * sizePadding
34+
35+
36+sizeRow =
37+ totalSizeElement + totalSpacing + totalPadding
38+
39+
40+main : Html msg
41+main =
42+ layout [ width fill, height fill ] <|
43+ -- The row should have 4.5px of padding to get
44+ -- from the 5.5px of margin of the elements on the edge
45+ -- up to 10px of padding specified on the wrappedRow.
46+ -- Instead the row has 5px of padding.
47+ wrappedRow [ width (px sizeRow), padding sizePadding, spacing sizeSpacing, Background.color (rgb 0 0 1) ]
48+ <|
49+ List.repeat nbElement <|
50+ -- Each element has a margin of 5.5px (11px of spacing / 2)
51+ el [ width (px sizeElement), height (px sizeElement), Background.color (rgb 1 0 0) ]
52+ <|
53+ el [ centerX, centerY ] <|
54+ text "card"
tests-rendering/cases/resolved/Layout/SafariBugIssue147.elmnew file+37
@@ -0,0 +1,37 @@
1+module Layout.SafariBugIssue147 exposing (view)
2+
3+{-|
4+
5+
6+# Safari bug for `el` heigh calculation in combination with `height fill`
7+
8+The problem appears to be that the height of the first el is 0, and therefore the second
9+text is rendered on the first.
10+
11+Versions
12+
13+OS: macOS Mojave 10.14.5
14+Browser: Safari
15+Browser Version: 12.1.1 (14607.2.6.1.1)
16+Elm Version: 0.19
17+Elm UI Version: 1.1.5
18+
19+<https://github.com/mdgriffith/elm-ui/issues/147>
20+
21+I was able to pinpoint the issue using git bisect to this fd08f1a commit, which lines up.
22+
23+<https://github.com/mdgriffith/elm-ui/commit/fd08f1a953484ba96f2d05037d4f208eab351514>
24+
25+-}
26+
27+import Testable.Element exposing (..)
28+
29+
30+view =
31+ layout [ height fill ] <|
32+ el [ height fill ] <|
33+ column
34+ [ height fill ]
35+ [ el [] <| text "Element that Safari gives height 0, if inside an el and not just text."
36+ , text "Text below the el above"
37+ ]
tests-rendering/cases/resolved/Layout/WrapRow.elmnew file+13
@@ -0,0 +1,13 @@
1+module WrapRow exposing (main)
2+
3+import Browser
4+import Element exposing (..)
5+
6+
7+main =
8+ layout [] <|
9+ wrappedRow
10+ [ padding 10
11+ , spacingXY 6 5
12+ ]
13+ [ text "Higher by 1 px" ]
tests-rendering/cases/resolved/Misc/Scroll.elmnew file+48
@@ -0,0 +1,48 @@
1+module Scroll exposing (main)
2+
3+import Browser
4+import Element exposing (Element, alignTop, centerX, centerY, column, el, fill, fillPortion, height, inFront, layoutWith, none, padding, px, row, scrollbarY, spacing, text, width, wrappedRow)
5+import Element.Background as Background
6+import Element.Font as Font
7+import Element.Input as Input exposing (button)
8+import Html exposing (Html)
9+import Html.Attributes
10+
11+
12+type alias Model =
13+ ()
14+
15+
16+type alias Msg =
17+ ()
18+
19+
20+field i =
21+ text <| "Scrolling text " ++ String.fromInt i
22+
23+
24+view : Model -> Html Msg
25+view model =
26+ layoutWith { options = [] } [ height fill ] <|
27+ row
28+ [ height fill ]
29+ [ column
30+ [ height fill
31+ , scrollbarY
32+
33+ -- The width fill is required, when using scrollbarY above
34+ -- else the width is set to 0.
35+ --, width fill
36+ ]
37+ (List.map field (List.range 1 100))
38+ , text "Non scrolling text"
39+ ]
40+
41+
42+main : Program () Model Msg
43+main =
44+ Browser.sandbox
45+ { init = ()
46+ , view = view
47+ , update = \msg model -> model
48+ }
tests-rendering/cases/resolved/Nearby/InFrontIssue.elmnew file+64
@@ -0,0 +1,64 @@
1+module Nearby.InFrontIssue exposing (view)
2+
3+import Browser
4+import Element as Ui exposing (..)
5+import Element.Background as Background
6+import Element.Font as Font
7+import Html exposing (Html)
8+
9+
10+view : Html Msg
11+view =
12+ let
13+ a =
14+ el
15+ [ width fill
16+ , height <| px 30
17+ , Background.color <| rgb 0 1 0
18+ ]
19+ <|
20+ text "A"
21+
22+ b =
23+ column
24+ [ width fill
25+ , height <| px 5000
26+ , Background.color <| rgb 1 0 1
27+ , spacing 60
28+ ]
29+ [ text "B"
30+ , c
31+ ]
32+
33+ c =
34+ el
35+ [ width <| px 100
36+ , height <| px 100
37+ , Background.color <| rgb 0 0 0
38+ , Font.color <| rgb 1 1 1
39+ , paddingXY 0 30
40+ , centerX
41+ , above d
42+ , below d
43+ , onLeft d
44+ , onRight d
45+ ]
46+ <|
47+ text "C"
48+
49+ d =
50+ el
51+ [ width <| px 100
52+ , height <| px 100
53+ , centerX
54+ , Background.color <| rgb 1 1 1
55+ , Font.color <| rgb 0 0 0
56+ ]
57+ <|
58+ text "D"
59+ in
60+ layout
61+ [ inFront a
62+ , paddingXY 0 30
63+ ]
64+ b
tests-rendering/cases/resolved/Nearby/Issue22ZIndex.elmnew file+87
@@ -0,0 +1,87 @@
1+module Nearby.Issue22ZIndex exposing (main)
2+
3+import Browser
4+import Element as Ui exposing (..)
5+import Element.Background as Background
6+import Element.Font as Font
7+import Html exposing (Html)
8+
9+
10+type alias Model =
11+ {}
12+
13+
14+initialModel : Model
15+initialModel =
16+ {}
17+
18+
19+type Msg
20+ = NoOp
21+
22+
23+update : Msg -> Model -> Model
24+update msg model =
25+ model
26+
27+
28+view : Model -> Html Msg
29+view model =
30+ let
31+ a =
32+ el
33+ [ width fill
34+ , height <| px 30
35+ , Background.color <| rgb 0 1 0
36+ ]
37+ <|
38+ text "A"
39+
40+ b =
41+ column
42+ [ width fill
43+ , height <| px 5000
44+ , Background.color <| rgb 1 0 1
45+ , spacing 60
46+ ]
47+ [ text "B"
48+ , c
49+ ]
50+
51+ c =
52+ el
53+ [ width fill
54+ , height <| px 100
55+ , Background.color <| rgb 0 0 0
56+ , Font.color <| rgb 1 1 1
57+ , paddingXY 0 30
58+ , inFront d
59+ ]
60+ <|
61+ text "C"
62+
63+ d =
64+ el
65+ [ width <| px 100
66+ , height <| px 100
67+ , centerX
68+ , Background.color <| rgb 1 1 1
69+ , Font.color <| rgb 0 0 0
70+ ]
71+ <|
72+ text "D"
73+ in
74+ layout
75+ [ inFront a
76+ , paddingXY 0 30
77+ ]
78+ b
79+
80+
81+main : Program () Model Msg
82+main =
83+ Browser.sandbox
84+ { init = initialModel
85+ , view = view
86+ , update = update
87+ }
tests-rendering/cases/resolved/Nearby/OtherInFrontIssue.elmnew file+55
@@ -0,0 +1,55 @@
1+module Nearby.OtherInFrontIssue exposing (main)
2+
3+import Browser
4+import Element exposing (Element)
5+import Element.Background as Background
6+import Html exposing (Html, button, div, text)
7+import Html.Attributes
8+import Html.Events exposing (onClick)
9+
10+
11+
12+-- helping hack
13+
14+
15+translateLeft : Element.Attribute msg
16+translateLeft =
17+ Html.Attributes.style "transform" "translate(-100%)"
18+ |> Element.htmlAttribute
19+
20+
21+main =
22+ Element.layout
23+ [ Element.inFront <|
24+ Element.el
25+ [ Element.alignLeft
26+ , Background.color <| Element.rgb 1 0.5 0.5
27+ , Element.height Element.fill
28+ ]
29+ <|
30+ Element.text "Side Menu .........."
31+ ]
32+ contentPane
33+
34+
35+contentPane =
36+ Element.column
37+ [ Element.width Element.fill
38+ , Element.height Element.fill
39+ , Background.color <| Element.rgb 1 0 0
40+ ]
41+ [ Element.el
42+ [ Element.centerX
43+ , Element.centerY
44+ , Element.onLeft <| Element.text " [ onLeft. onLeft onLeft onLeft onLeft onLeft onLeft ] "
45+ ]
46+ (Element.text " [ Content: This will remain behind the Side Menu. ]")
47+ , Element.el
48+ [ Element.centerX
49+ , Element.centerY
50+ , Element.behindContent <|
51+ Element.el [ translateLeft ] <|
52+ Element.text " [ behindContent + translateLeft. behindContent + translateLeft ] "
53+ ]
54+ (Element.text " [ Content: This will remain behind the Side Menu. ]")
55+ ]
tests-rendering/cases/resolved/Nearby/ZIndexRegression.elmnew file+43
@@ -0,0 +1,43 @@
1+module Nearby.ZIndexRegression exposing (main)
2+
3+import Element exposing (..)
4+import Element.Background as Background
5+import Html exposing (Html)
6+
7+
8+main : Html msg
9+main =
10+ layout [] <|
11+ column [ width fill, height fill ]
12+ [ el
13+ [ width fill
14+ , height (px 100)
15+ , Background.color (rgb 0 0 1)
16+ , inFront menu
17+ ]
18+ none
19+ , el
20+ [ width fill
21+ , height fill
22+ , inFront menu
23+ ]
24+ none
25+ ]
26+
27+
28+menu : Element msg
29+menu =
30+ el
31+ [ transparent True
32+ , mouseOver [ transparent False ]
33+ , width fill
34+ , height fill
35+ , below <|
36+ el
37+ [ width fill
38+ , height (px 500)
39+ , Background.color (rgb 1 0 0)
40+ ]
41+ none
42+ ]
43+ none
tests-rendering/elm.json+21−24
@@ -1,28 +1,25 @@
1{
1{
2− "type": "application",
2+ "type": "application",
3− "source-directories": [
3+ "source-directories": ["src", "../src", "cases/open", "cases/resolved"],
4− "src",
5− "../src"
6− ],
7− "elm-version": "0.19.1",
4+ "elm-version": "0.19.1",
8− "dependencies": {
5+ "dependencies": {
9− "direct": {
6+ "direct": {
10− "elm/browser": "1.0.2",
7+ "elm/browser": "1.0.2",
11− "elm/core": "1.0.0",
8+ "elm/core": "1.0.0",
12− "elm/html": "1.0.0",
9+ "elm/html": "1.0.0",
13− "elm/json": "1.0.0",
10+ "elm/json": "1.0.0",
14− "elm/parser": "1.1.0",
11+ "elm/parser": "1.1.0",
15− "elm/random": "1.0.0",
12+ "elm/random": "1.0.0",
16− "elm/time": "1.0.0",
13+ "elm/time": "1.0.0",
17− "elm/virtual-dom": "1.0.2",
14+ "elm/virtual-dom": "1.0.2",
18− "elm-explorations/test": "1.1.0"
15+ "elm-explorations/test": "1.1.0"
19− },
20− "indirect": {
21− "elm/url": "1.0.0"
22− }
23 },
16 },
24− "test-dependencies": {
25− "direct": {},
26− "indirect": {}
17+ "indirect": {
18+ "elm/url": "1.0.0"
27 }
19 }
20+ },
21+ "test-dependencies": {
22+ "direct": {},
23+ "indirect": {}
24+ }
28}
25}
tests-rendering/make.shdeleted−2
@@ -1,2 +0,0 @@
1−
2−elm-live cases/open/WeirdCentering.elm --dir=view -- --output=view/elm.js --debug
tests-rendering/src/Testable.elm+91−7
@@ -19,6 +19,9 @@ module Testable exposing
19 , formatColorWithAlpha
19 , formatColorWithAlpha
20 , getIds
20 , getIds
21 , getSpacing
21 , getSpacing
22+ , getSpacingFromAttributes
23+ , lessThanOrEqual
24+ , rounded
22 , runTests
25 , runTests
23 , textHeight
26 , textHeight
24 , toElement
27 , toElement
@@ -39,6 +42,7 @@ import Test exposing (Test)
39
42
40type Element msg
43type Element msg
41 = El (List (Attr msg)) (Element msg)
44 = El (List (Attr msg)) (Element msg)
45+ | Link String (List (Attr msg)) (Element msg)
42 | Row (List (Attr msg)) (List (Element msg))
46 | Row (List (Attr msg)) (List (Element msg))
43 | Column (List (Attr msg)) (List (Element msg))
47 | Column (List (Attr msg)) (List (Element msg))
44 | TextColumn (List (Attr msg)) (List (Element msg))
48 | TextColumn (List (Attr msg)) (List (Element msg))
@@ -88,6 +92,9 @@ toElementType elem =
88 El _ _ ->
92 El _ _ ->
89 ElType
93 ElType
90
94
95+ Link _ _ _ ->
96+ ElType
97+
91 Row _ _ ->
98 Row _ _ ->
92 RowType
99 RowType
93
100
@@ -159,6 +166,9 @@ type LayoutContext
159 | InRow
166 | InRow
160 | InEl
167 | InEl
161 | InColumn
168 | InColumn
169+ | InParagraph
170+ | InTextCol
171+ | AtRoot
162
172
163
173
164type alias Surroundings msg =
174type alias Surroundings msg =
@@ -191,9 +201,21 @@ type alias TextMetrics =
191 }
201 }
192
202
193
203
204+{-| The font metrics we currently have are `actual`, meaning for the text actually rendered, not the font as a whole.
205+
206+We also know the font size is 20, so we're just going to return 20.
207+
208+TODO: improve font metric collection using something like opentype.js
209+
210+-}
194textHeight metrics =
211textHeight metrics =
212+ let
213+ actualHeight =
195− metrics.actualBoundingBoxAscent
214+ metrics.actualBoundingBoxAscent
196− + metrics.actualBoundingBoxDescent
215+ + metrics.actualBoundingBoxDescent
216+ in
217+ -- actualHeight / 20
218+ 20
197
219
198
220
199{-| -}
221{-| -}
@@ -237,6 +259,26 @@ type alias LayoutTest =
237{- Expectations -}
259{- Expectations -}
238
260
239
261
262+floatToString : Float -> String
263+floatToString x =
264+ String.fromFloat (toFloat (round (x * 100)) / 100)
265+
266+
267+lessThanOrEqual : String -> Float -> Float -> LayoutExpectation
268+lessThanOrEqual label one two =
269+ Expect
270+ { description = label ++ " " ++ floatToString one ++ " <= " ++ floatToString two
271+ , result = one <= two
272+ }
273+
274+
275+rounded : String -> { expected : Float, found : Float } -> LayoutExpectation
276+rounded label { expected, found } =
277+ true
278+ (label ++ "| expected " ++ floatToString expected ++ ", found " ++ floatToString found)
279+ (abs (expected - found) < 1)
280+
281+
240equal : a -> a -> LayoutExpectation
282equal : a -> a -> LayoutExpectation
241equal one two =
283equal one two =
242 Expect
284 Expect
@@ -293,6 +335,9 @@ getElementId level el =
293 El attrs child ->
335 El attrs child ->
294 id :: getElementId (0 :: level) child ++ attributeIDs attrs
336 id :: getElementId (0 :: level) child ++ attributeIDs attrs
295
337
338+ Link _ attrs child ->
339+ id :: getElementId (0 :: level) child ++ attributeIDs attrs
340+
296 Row attrs children ->
341 Row attrs children ->
297 id :: childrenIDs children ++ attributeIDs attrs
342 id :: childrenIDs children ++ attributeIDs attrs
298
343
@@ -323,7 +368,12 @@ toElement el =
323
368
324toHtml : Element msg -> Html msg
369toHtml : Element msg -> Html msg
325toHtml el =
370toHtml el =
326− Element.layout [ idAttr "0" ] <|
371+ Element.layout
372+ [ idAttr "0"
373+ , Element.width (Element.px 1000)
374+ , Element.height (Element.px 1000)
375+ ]
376+ <|
327 renderElement [ 0, 0 ] el
377 renderElement [ 0, 0 ] el
328
378
329
379
@@ -352,6 +402,13 @@ renderElement level el =
352 (id :: makeAttributes attrs)
402 (id :: makeAttributes attrs)
353 (renderElement (0 :: level) child)
403 (renderElement (0 :: level) child)
354
404
405+ Link url attrs child ->
406+ Element.link
407+ (id :: makeAttributes attrs)
408+ { url = url
409+ , label = renderElement (0 :: level) child
410+ }
411+
355 Row attrs children ->
412 Row attrs children ->
356 Element.row
413 Element.row
357 (id :: makeAttributes attrs)
414 (id :: makeAttributes attrs)
@@ -451,7 +508,7 @@ runTests harvested el =
451 , parentSpacing = 0
508 , parentSpacing = 0
452 , level = [ 0, 0 ]
509 , level = [ 0, 0 ]
453 , element = el
510 , element = el
454− , location = InEl
511+ , location = AtRoot
455 }
512 }
456
513
457
514
@@ -543,6 +600,9 @@ createTest { siblings, parent, cache, level, element, location, parentSpacing }
543 El _ _ ->
600 El _ _ ->
544 InEl
601 InEl
545
602
603+ Link _ _ _ ->
604+ InEl
605+
546 Row _ _ ->
606 Row _ _ ->
547 InRow
607 InRow
548
608
@@ -550,10 +610,10 @@ createTest { siblings, parent, cache, level, element, location, parentSpacing }
550 InColumn
610 InColumn
551
611
552 TextColumn _ _ ->
612 TextColumn _ _ ->
553− InColumn
613+ InTextCol
554
614
555 Paragraph _ _ ->
615 Paragraph _ _ ->
556− InRow
616+ InParagraph
557
617
558 Text _ ->
618 Text _ ->
559 InEl
619 InEl
@@ -669,6 +729,9 @@ createTest { siblings, parent, cache, level, element, location, parentSpacing }
669 El attrs child ->
729 El attrs child ->
670 tests self attrs [ child ]
730 tests self attrs [ child ]
671
731
732+ Link _ attrs child ->
733+ tests self attrs [ child ]
734+
672 Row attrs children ->
735 Row attrs children ->
673 tests self attrs children
736 tests self attrs children
674
737
@@ -739,7 +802,7 @@ createAttributeTest parent cache level attrIndex surroundings attr =
739
802
740 Batch batch ->
803 Batch batch ->
741 batch
804 batch
742− |> List.indexedMap (\i attribute -> createAttributeTest parent cache (attrIndex :: level) i surroundings attribute)
805+ |> List.indexedMap (\i attribute -> createAttributeTest parent cache level i surroundings attribute)
743 |> List.concat
806 |> List.concat
744
807
745 LabeledTest { label, test } ->
808 LabeledTest { label, test } ->
@@ -757,6 +820,9 @@ addAttribute attr el =
757 El attrs child ->
820 El attrs child ->
758 El (attr :: attrs) child
821 El (attr :: attrs) child
759
822
823+ Link url attrs child ->
824+ Link url (attr :: attrs) child
825+
760 Row attrs children ->
826 Row attrs children ->
761 Row (attr :: attrs) children
827 Row (attr :: attrs) children
762
828
@@ -812,6 +878,21 @@ formatColor (Internal.Rgba red green blue alpha) =
812 ++ ")"
878 ++ ")"
813
879
814
880
881+getSpacingFromAttributes attrs =
882+ case attrs of
883+ [] ->
884+ 0
885+
886+ (Spacing i) :: remain ->
887+ i
888+
889+ (Batch batched) :: remain ->
890+ getSpacingFromAttributes (batched ++ remain)
891+
892+ _ :: remain ->
893+ getSpacingFromAttributes remain
894+
895+
815getSpacing : Element msg -> Maybe Int
896getSpacing : Element msg -> Maybe Int
816getSpacing el =
897getSpacing el =
817 let
898 let
@@ -837,6 +918,9 @@ getSpacing el =
837 El attrs _ ->
918 El attrs _ ->
838 filterAttrs attrs
919 filterAttrs attrs
839
920
921+ Link _ attrs _ ->
922+ filterAttrs attrs
923+
840 Row attrs _ ->
924 Row attrs _ ->
841 filterAttrs attrs
925 filterAttrs attrs
842
926
tests-rendering/src/Testable/Element.elm+364−93
@@ -10,6 +10,7 @@ module Testable.Element exposing
10 , below
10 , below
11 , centerX
11 , centerX
12 , centerY
12 , centerY
13+ , clip
13 , column
14 , column
14 , el
15 , el
15 , expectRoundedEquality
16 , expectRoundedEquality
@@ -20,6 +21,7 @@ module Testable.Element exposing
20 , isVisible
21 , isVisible
21 , label
22 , label
22 , layout
23 , layout
24+ , link
23 , maximum
25 , maximum
24 , minimum
26 , minimum
25 , moveDown
27 , moveDown
@@ -36,10 +38,14 @@ module Testable.Element exposing
36 , rgb
38 , rgb
37 , rgba
39 , rgba
38 , row
40 , row
41+ , scrollbarX
42+ , scrollbarY
43+ , scrollbars
39 , shrink
44 , shrink
40 , spacing
45 , spacing
41 , text
46 , text
42 , textColumn
47 , textColumn
48+ , toProgram
43 , transparent
49 , transparent
44 , width
50 , width
45 )
51 )
@@ -63,11 +69,16 @@ import Testable
63import Testable.Runner
69import Testable.Runner
64
70
65
71
72+{-| This is used when we want to run all tests in a test suite instead of one at a time.
73+-}
74+toProgram : Testable.Runner.Testable -> Testable.Runner.TestableProgram
75+toProgram testable =
76+ Testable.Runner.program [ testable ]
77+
78+
66−layout : List (Testable.Attr msg) -> Testable.Element Testable.Runner.Msg -> Testable.Runner.TestableProgram
79+layout : List (Testable.Attr msg) -> Testable.Element Testable.Runner.Msg -> Testable.Runner.Testable
67layout attrs elem =
80layout attrs elem =
68− Testable.Runner.program
81+ Testable.Runner.testable "Test" elem
69− [ ( "Tests Run", elem )
70− ]
71
82
72
83
73text : String -> Testable.Element msg
84text : String -> Testable.Element msg
@@ -97,12 +108,59 @@ none =
97
108
98paragraph : List (Testable.Attr msg) -> List (Testable.Element msg) -> Testable.Element msg
109paragraph : List (Testable.Attr msg) -> List (Testable.Element msg) -> Testable.Element msg
99paragraph attrs =
110paragraph attrs =
100− Testable.Paragraph (implicitWidthHeightShrink attrs)
111+ let
112+ withImplicits =
113+ implicitTest (widthHelper Nothing Nothing (Fill 1))
114+ :: implicitTest (heightHelper Nothing Nothing Shrink)
115+ :: attrs
116+ in
117+ Testable.Paragraph (skipOverridden withImplicits)
101
118
102
119
103textColumn : List (Testable.Attr msg) -> List (Testable.Element msg) -> Testable.Element msg
120textColumn : List (Testable.Attr msg) -> List (Testable.Element msg) -> Testable.Element msg
104textColumn attrs =
121textColumn attrs =
122+ let
123+ withImplicits =
124+ implicitTest (widthHelper (Just 500) (Just 750) (Fill 1))
125+ :: implicitTest (heightHelper Nothing Nothing Shrink)
126+ :: attrs
127+ in
128+ Testable.TextColumn (skipOverridden withImplicits)
129+
130+
131+link :
132+ List (Testable.Attr msg)
133+ ->
134+ { url : String
135+ , label : Testable.Element msg
136+ }
137+ -> Testable.Element msg
138+link attrs details =
139+ Testable.Link details.url
105− Testable.TextColumn (implicitWidthHeightShrink attrs)
140+ (implicitWidthHeightShrink attrs)
141+ details.label
142+
143+
144+clip =
145+ Testable.Attr Element.clip
146+
147+
148+{-| -}
149+scrollbars : Testable.Attr msg
150+scrollbars =
151+ Testable.Attr Element.scrollbars
152+
153+
154+{-| -}
155+scrollbarY : Testable.Attr msg
156+scrollbarY =
157+ Testable.Attr Element.scrollbarY
158+
159+
160+{-| -}
161+scrollbarX : Testable.Attr msg
162+scrollbarX =
163+ Testable.Attr Element.scrollbarX
106
164
107
165
108{-| Old labeling mechanism that i removed to hastily
166{-| Old labeling mechanism that i removed to hastily
@@ -276,6 +334,11 @@ paddingXY x y =
276 }
334 }
277
335
278
336
337+listIf ls =
338+ List.filter Tuple.first ls
339+ |> List.map Tuple.second
340+
341+
279widthHelper maybeMin maybeMax len =
342widthHelper maybeMin maybeMax len =
280 let
343 let
281 addMin l =
344 addMin l =
@@ -344,7 +407,10 @@ widthHelper maybeMin maybeMax len =
344 )
407 )
345 , test =
408 , test =
346 \found ->
409 \found ->
410+ [ expectRoundedEquality
411+ { expected = toFloat val
347− [ Testable.true "exact width is exact" (floor found.self.bbox.width == val)
412+ , found = found.self.bbox.width
413+ }
348 , Testable.true "min/max is upheld" (minMaxTest (floor found.self.bbox.width))
414 , Testable.true "min/max is upheld" (minMaxTest (floor found.self.bbox.width))
349 ]
415 ]
350 }
416 }
@@ -374,33 +440,93 @@ widthHelper maybeMin maybeMax len =
374 parentAvailableWidth =
440 parentAvailableWidth =
375 context.parent.bbox.width - (context.self.bbox.padding.left + context.self.bbox.padding.right)
441 context.parent.bbox.width - (context.self.bbox.padding.left + context.self.bbox.padding.right)
376 in
442 in
443+ List.concat
377− [ case context.parentLayout of
444+ [ case context.parentLayout of
378− Testable.IsNearby _ ->
445+ Testable.IsNearby _ ->
379− Testable.true "Nearby Element has fill width"
446+ [ Testable.true "Nearby Element has fill width"
380− ((floor context.parent.bbox.width == floor context.self.bbox.width)
447+ ((floor context.parent.bbox.width == floor context.self.bbox.width)
381− || minMaxTest (floor context.self.bbox.width)
448+ || minMaxTest (floor context.self.bbox.width)
382− )
449+ )
383−
450+ ]
384− Testable.InColumn ->
385− Testable.true "Element within column has fill width"
386− ((floor parentAvailableWidth == floor context.self.bbox.width)
387− || minMaxTest (floor context.self.bbox.width)
388− )
389
451
452+ Testable.InColumn ->
453+ [ Testable.true "Element within column has fill width"
454+ ((floor parentAvailableWidth == floor context.self.bbox.width)
455+ || minMaxTest (floor context.self.bbox.width)
456+ )
457+ ]
458+
390− Testable.InEl ->
459+ Testable.InEl ->
391− Testable.true "Element within element has fill width" <|
460+ [ Testable.true "Element within element has fill width" <|
392− (floor parentAvailableWidth == floor context.self.bbox.width)
461+ (floor parentAvailableWidth == floor context.self.bbox.width)
462+ || minMaxTest (floor context.self.bbox.width)
463+ ]
464+
465+ _ ->
466+ let
467+ spacePerPortion =
468+ parentAvailableWidth / toFloat (List.length context.siblings + 1)
469+ in
470+ [ Testable.true "element has fill width" <|
471+ (floor spacePerPortion == floor context.self.bbox.width)
393− || minMaxTest (floor context.self.bbox.width)
472+ || minMaxTest (floor context.self.bbox.width)
473+ ]
474+ , [ Testable.lessThanOrEqual "not larger than parent"
475+ context.self.bbox.width
476+ context.parent.bbox.width
477+ ]
478+ , case context.selfElement of
479+ Testable.Paragraph _ _ ->
480+ -- A paragraph with width fill
481+ -- we want to test for correct text wrapping here.
482+ --
483+ let
484+ childWidth child =
485+ child.bbox.width
486+
487+ totalChildren =
488+ context.children
489+ |> List.map childWidth
490+ |> List.append (List.map .width context.self.textMetrics)
491+ |> List.sum
492+
493+ horizontalPadding =
494+ context.self.bbox.padding.left + context.self.bbox.padding.right
495+
496+ totalCalculatedWidth =
497+ totalChildren + horizontalPadding
498+
499+ expectedLines =
500+ if boxChildrenHeight > 20 then
501+ ceiling (boxChildrenHeight / 20)
502+
503+ else
504+ ceiling (totalCalculatedWidth / context.self.bbox.width)
505+
506+ boxChildrenHeight =
507+ context.children
508+ |> List.map
509+ (\c ->
510+ c.bbox.height
511+ )
512+ |> List.sum
513+ in
514+ [ Testable.true "text wrapping, checking height"
515+ -- all we're doing here is testing if wrapping is occurring
516+ -- not the exact height, which is a little tricky to calculate perfectly without more information.
517+ (if expectedLines > 1 then
518+ context.self.bbox.height >= (20 * 2)
519+
520+ else
521+ -- then it's less than 2 ~ line heights
522+ -- there's some weird variance here which makes it hard to be exact.
523+ context.self.bbox.height < (20 * 2)
524+ )
525+ ]
394
526
395− _ ->
527+ _ ->
396− let
528+ []
397− spacePerPortion =
398− parentAvailableWidth / toFloat (List.length context.siblings + 1)
399− in
400− Testable.true "element has fill width" <|
401− (floor spacePerPortion == floor context.self.bbox.width)
402− || minMaxTest (floor context.self.bbox.width)
403− ]
529+ ]
404 }
530 }
405
531
406 Shrink ->
532 Shrink ->
@@ -430,13 +556,51 @@ widthHelper maybeMin maybeMax len =
430 horizontalPadding =
556 horizontalPadding =
431 context.self.bbox.padding.left + context.self.bbox.padding.right
557 context.self.bbox.padding.left + context.self.bbox.padding.right
432 in
558 in
433− [ expectRoundedEquality
559+ listIf
560+ [ ( (context.parentLayout /= Testable.InParagraph)
561+ && (context.parentLayout /= Testable.InTextCol)
562+ , Testable.rounded "equals children"
434− { expected = totalChildren + horizontalPadding
563+ { expected = totalChildren + horizontalPadding
435− , found = context.self.bbox.width
564+ , found = context.self.bbox.width
436− }
565+ }
566+ )
567+ , ( context.parentLayout /= Testable.AtRoot
568+ , Testable.lessThanOrEqual "not larger than parent"
569+ context.self.bbox.width
570+ context.parent.bbox.width
571+ )
437− ]
572+ ]
438
573
439− Testable.Row _ _ ->
574+ Testable.Link _ _ _ ->
575+ let
576+ childWidth child =
577+ child.bbox.width
578+
579+ totalChildren =
580+ context.children
581+ |> List.map childWidth
582+ |> List.append (List.map .width context.self.textMetrics)
583+ |> List.sum
584+
585+ horizontalPadding =
586+ context.self.bbox.padding.left + context.self.bbox.padding.right
587+ in
588+ listIf
589+ [ ( (context.parentLayout /= Testable.InParagraph)
590+ && (context.parentLayout /= Testable.InTextCol)
591+ , Testable.rounded "equals children"
592+ { expected = totalChildren + horizontalPadding
593+ , found = context.self.bbox.width
594+ }
595+ )
596+ , ( context.parentLayout /= Testable.AtRoot
597+ , Testable.lessThanOrEqual "not larger than parent"
598+ context.self.bbox.width
599+ context.parent.bbox.width
600+ )
601+ ]
602+
603+ Testable.Row rowAttrs _ ->
440 -- width of row is the sum of all children widths
604 -- width of row is the sum of all children widths
441 -- both text elements and others.
605 -- both text elements and others.
442 let
606 let
@@ -452,14 +616,25 @@ widthHelper maybeMin maybeMax len =
452 horizontalPadding =
616 horizontalPadding =
453 context.self.bbox.padding.left + context.self.bbox.padding.right
617 context.self.bbox.padding.left + context.self.bbox.padding.right
454
618
455− spacingValue =
619+ spacingAmount =
620+ Testable.getSpacingFromAttributes rowAttrs
621+
622+ totalSpacing =
456− toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
623+ toFloat spacingAmount * (toFloat (List.length context.children) - 1)
457 in
624 in
625+ listIf
626+ [ ( True
458− [ expectRoundedEquality
627+ , expectRoundedEquality
459− { expected = totalChildren + horizontalPadding + spacingValue
628+ { expected = totalChildren + horizontalPadding + totalSpacing
460− , found = context.self.bbox.width
629+ , found = context.self.bbox.width
461− }
630+ }
631+ )
632+ , ( context.parentLayout /= Testable.AtRoot
633+ , Testable.lessThanOrEqual "not larger than parent"
634+ context.self.bbox.width
635+ context.parent.bbox.width
636+ )
462− ]
637+ ]
463
638
464 Testable.Column _ _ ->
639 Testable.Column _ _ ->
465 -- The width of the column is the width of the widest child.
640 -- The width of the column is the width of the widest child.
@@ -483,14 +658,55 @@ widthHelper maybeMin maybeMax len =
483 |> List.map childWidth
658 |> List.map childWidth
484 |> List.append textChildren
659 |> List.append textChildren
485 in
660 in
661+ listIf
662+ [ ( True
486− [ expectRoundedEquality
663+ , expectRoundedEquality
487− { expected = Maybe.withDefault 0 (List.maximum allChildren)
664+ { expected = Maybe.withDefault 0 (List.maximum allChildren)
488− , found = context.self.bbox.width
665+ , found = context.self.bbox.width
489− }
666+ }
667+ )
668+ , ( context.parentLayout /= Testable.AtRoot
669+ , Testable.lessThanOrEqual "not larger than parent"
670+ context.self.bbox.width
671+ context.parent.bbox.width
672+ )
490− ]
673+ ]
491
674
492 Testable.TextColumn _ _ ->
675 Testable.TextColumn _ _ ->
676+ -- The width of the column is the width of the widest child.
677+ let
678+ childWidth child =
679+ child.bbox.width
680+ + context.self.bbox.padding.left
681+ + context.self.bbox.padding.right
682+
683+ textChildren =
684+ List.map
685+ (\txt ->
686+ txt.width
687+ + context.self.bbox.padding.left
688+ + context.self.bbox.padding.right
689+ )
690+ context.self.textMetrics
691+
692+ allChildren =
693+ context.children
694+ |> List.map childWidth
695+ |> List.append textChildren
696+ in
697+ listIf
698+ [ ( True
699+ , expectRoundedEquality
700+ { expected = Maybe.withDefault 0 (List.maximum allChildren)
701+ , found = context.self.bbox.width
702+ }
703+ )
704+ , ( context.parentLayout /= Testable.AtRoot
705+ , Testable.lessThanOrEqual "not larger than parent"
706+ context.self.bbox.width
707+ context.parent.bbox.width
708+ )
493− []
709+ ]
494
710
495 Testable.Paragraph _ _ ->
711 Testable.Paragraph _ _ ->
496 -- This should be the size it's text,
712 -- This should be the size it's text,
@@ -508,11 +724,19 @@ widthHelper maybeMin maybeMax len =
508 horizontalPadding =
724 horizontalPadding =
509 context.self.bbox.padding.left + context.self.bbox.padding.right
725 context.self.bbox.padding.left + context.self.bbox.padding.right
510 in
726 in
727+ listIf
728+ [ ( True
511− [ expectRoundedEquality
729+ , expectRoundedEquality
512− { expected = totalChildren + horizontalPadding
730+ { expected = totalChildren + horizontalPadding
513− , found = context.self.bbox.width
731+ , found = context.self.bbox.width
514− }
732+ }
733+ )
734+ , ( context.parentLayout /= Testable.AtRoot
735+ , Testable.lessThanOrEqual "not larger than parent"
736+ context.self.bbox.width
737+ context.parent.bbox.width
738+ )
515− ]
739+ ]
516
740
517 Testable.Text _ ->
741 Testable.Text _ ->
518 []
742 []
@@ -590,8 +814,10 @@ heightHelper maybeMin maybeMax len =
590 , id = Testable.IsHeight
814 , id = Testable.IsHeight
591 , test =
815 , test =
592 \found ->
816 \found ->
593− [ Testable.true ("exact height is exact: " ++ String.fromInt (floor found.self.bbox.height) ++ "," ++ String.fromInt val)
817+ [ expectRoundedEquality
818+ { expected = toFloat val
594− (floor found.self.bbox.height == val)
819+ , found = found.self.bbox.height
820+ }
595 , Testable.true "min/max holds true"
821 , Testable.true "min/max holds true"
596 (minMaxTest (floor found.self.bbox.height))
822 (minMaxTest (floor found.self.bbox.height))
597 ]
823 ]
@@ -662,49 +888,88 @@ heightHelper maybeMin maybeMax len =
662 Testable.El _ _ ->
888 Testable.El _ _ ->
663 let
889 let
664 childHeight child =
890 childHeight child =
665− -- TODO: add margin values to heights
666 child.bbox.height
891 child.bbox.height
892+ in
893+ if List.isEmpty context.children then
894+ -- context.self.textMetrics
895+ -- |> List.map Testable.textHeight
896+ -- |> List.sum
897+ -- TODO: apparently the font metrics we have are for the literal characters rendered
898+ -- not for the font itself.
899+ [ Testable.todo "calculate height from actual text metrics"
900+ ]
667
901
668− totalChildren =
902+ else
903+ [ expectRoundedEquality
904+ { expected =
669− context.children
905+ context.children
670− |> List.map childHeight
906+ |> List.map childHeight
671− |> List.append (List.map Testable.textHeight context.self.textMetrics)
672− |> List.sum
907+ |> List.sum
673−
674− verticalPadding =
675− context.self.bbox.padding.top + context.self.bbox.padding.bottom
908+ |> (\h -> h + context.self.bbox.padding.top + context.self.bbox.padding.bottom)
909+ , found = context.self.bbox.height
910+ }
911+ , Testable.lessThanOrEqual "not larger than parent"
912+ context.self.bbox.height
913+ context.parent.bbox.height
914+ ]
676
915
677− spacingValue =
916+ Testable.Link _ _ _ ->
678− toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
917+ let
918+ childHeight child =
919+ child.bbox.height
679 in
920 in
921+ if List.isEmpty context.children then
922+ -- context.self.textMetrics
923+ -- |> List.map Testable.textHeight
924+ -- |> List.sum
925+ -- TODO: apparently the font metrics we have are for the literal characters rendered
926+ -- not for the font itself.
927+ [ Testable.todo "calculate height from actual text metrics"
928+ ]
929+
930+ else
680− [ expectRoundedEquality
931+ [ expectRoundedEquality
681− { expected = totalChildren + verticalPadding + spacingValue
932+ { expected =
933+ context.children
934+ |> List.map childHeight
935+ |> List.sum
936+ |> (\h -> h + context.self.bbox.padding.top + context.self.bbox.padding.bottom)
682− , found = context.self.bbox.height
937+ , found = context.self.bbox.height
683− }
938+ }
939+ , Testable.lessThanOrEqual "not larger than parent"
940+ context.self.bbox.height
941+ context.parent.bbox.height
684− ]
942+ ]
685
943
686 Testable.Row _ _ ->
944 Testable.Row _ _ ->
687 let
945 let
688 childHeight child =
946 childHeight child =
689 child.bbox.height
947 child.bbox.height
690−
691− totalChildren =
692− context.children
693− |> List.map childHeight
694− |> List.append (List.map Testable.textHeight context.self.textMetrics)
695− |> List.maximum
696− |> Maybe.withDefault 0
697−
698− verticalPadding =
699− context.self.bbox.padding.top + context.self.bbox.padding.bottom
700 in
948 in
949+ if List.isEmpty context.children then
950+ -- context.self.textMetrics
951+ -- |> List.map Testable.textHeight
952+ -- |> List.sum
953+ -- TODO: apparently the font metrics we have are for the literal characters rendered
954+ -- not for the font itself.
955+ [ Testable.todo "calculate height from actual text metrics" ]
956+
957+ else
701− [ expectRoundedEquality
958+ [ expectRoundedEquality
702− { expected = totalChildren + verticalPadding
959+ { expected =
960+ context.children
961+ |> List.map childHeight
962+ |> List.maximum
963+ |> Maybe.withDefault 0
964+ |> (\h -> h + context.self.bbox.padding.top + context.self.bbox.padding.bottom)
703− , found = context.self.bbox.height
965+ , found = context.self.bbox.height
704− }
966+ }
967+ , Testable.lessThanOrEqual "not larger than parent"
968+ context.self.bbox.height
969+ context.parent.bbox.height
705− ]
970+ ]
706
971
707− Testable.Column _ _ ->
972+ Testable.Column colAttrs _ ->
708 let
973 let
709 childHeight child =
974 childHeight child =
710 child.bbox.height
975 child.bbox.height
@@ -718,13 +983,19 @@ heightHelper maybeMin maybeMax len =
718 verticalPadding =
983 verticalPadding =
719 context.self.bbox.padding.top + context.self.bbox.padding.bottom
984 context.self.bbox.padding.top + context.self.bbox.padding.bottom
720
985
721− spacingValue =
986+ spacingAmount =
987+ Testable.getSpacingFromAttributes colAttrs
988+
989+ totalSpacing =
722− toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
990+ toFloat spacingAmount * (toFloat (List.length context.children) - 1)
723 in
991 in
724 [ expectRoundedEquality
992 [ expectRoundedEquality
725− { expected = totalChildren + verticalPadding + spacingValue
993+ { expected = totalChildren + verticalPadding + totalSpacing
726 , found = context.self.bbox.height
994 , found = context.self.bbox.height
727 }
995 }
996+ , Testable.lessThanOrEqual "not larger than parent"
997+ context.self.bbox.height
998+ context.parent.bbox.height
728 ]
999 ]
729
1000
730 Testable.TextColumn _ _ ->
1001 Testable.TextColumn _ _ ->
tests-rendering/src/Testable/Element/Font.elm+6−1
@@ -1,4 +1,4 @@
1−module Testable.Element.Font exposing (color)
1+module Testable.Element.Font exposing (bold, color, size)
2
2
3{-| -}
3{-| -}
4
4
@@ -8,6 +8,11 @@ import Element.Font as Font
8import Testable
8import Testable
9
9
10
10
11+bold : Testable.Attr msg
12+bold =
13+ Testable.Attr Font.bold
14+
15+
11color : Color -> Testable.Attr msg
16color : Color -> Testable.Attr msg
12color clr =
17color clr =
13 Testable.LabeledTest
18 Testable.LabeledTest
tests-rendering/src/Testable/Generator.elmnew file+398
@@ -0,0 +1,398 @@
1+module Testable.Generator exposing (..)
2+
3+{-| -}
4+
5+import Testable
6+import Testable.Element exposing (..)
7+import Testable.Element.Background as Background
8+import Testable.Element.Font as Font
9+
10+
11+{-| Given a list of attributes, generate every context this list of attributes could be in.
12+
13+So, this means,
14+
15+ - every element type
16+ - in every element type
17+
18+-}
19+element : String -> List (Testable.Attr msg) -> List ( String, Testable.Element msg )
20+element label attrs =
21+ -- [ ( label, paragraph attrs [ short ] )
22+ -- ]
23+ mapEveryCombo
24+ (\( selfLabel, makeSelf ) ( childLabel, child ) ->
25+ ( label ++ " - " ++ selfLabel ++ " > " ++ childLabel
26+ , makeSelf attrs child
27+ )
28+ )
29+ layouts
30+ contents
31+
32+
33+{-| Given a list of attributes, generate every context this list of attributes could be in.
34+
35+So, this means,
36+
37+ - every element type
38+ - in every element type
39+
40+-}
41+elementInLayout : String -> List (Testable.Attr msg) -> List ( String, Testable.Element msg )
42+elementInLayout label attrs =
43+ mapEveryCombo3
44+ (\( layoutLabel, makeLayout ) ( selfLabel, makeSelf ) ( childLabel, child ) ->
45+ ( label ++ " - " ++ layoutLabel ++ " > " ++ selfLabel ++ " > " ++ childLabel
46+ , makeLayout [] (makeSelf attrs child)
47+ )
48+ )
49+ layouts
50+ layouts
51+ contents
52+
53+
54+{-| Sometimes we want to try a whole bunch of combinations of attributes
55+
56+This makes it a bit easier to construct
57+
58+-}
59+elementWith : String -> List ( String, List (Testable.Attr msg) ) -> List ( String, Testable.Element msg )
60+elementWith label labelAttrs =
61+ mapEveryCombo3
62+ (\( attrLabel, attrs ) ( selfLabel, makeSelf ) ( childLabel, child ) ->
63+ ( label ++ " - " ++ selfLabel ++ " with " ++ attrLabel ++ " > " ++ childLabel
64+ , makeSelf attrs child
65+ )
66+ )
67+ labelAttrs
68+ layouts
69+ contents
70+
71+
72+{-| This varies the layout element that an element is in.
73+-}
74+elementInLayoutWith :
75+ String
76+ ->
77+ List
78+ ( String
79+ , { self : List (Testable.Attr msg)
80+ , parent : List (Testable.Attr msg)
81+ }
82+ )
83+ -> List ( String, Testable.Element msg )
84+elementInLayoutWith label labelAttrs =
85+ mapEveryCombo4
86+ (\( attrLabel, attrs ) ( layoutLabel, makeLayout ) ( selfLabel, makeSelf ) ( childLabel, child ) ->
87+ ( label ++ " - " ++ layoutLabel ++ " > " ++ selfLabel ++ " with " ++ attrLabel ++ " > " ++ childLabel
88+ , makeLayout attrs.parent (makeSelf attrs.self child)
89+ )
90+ )
91+ labelAttrs
92+ allLayouts
93+ layouts
94+ contents
95+
96+
97+layouts =
98+ [ ( "el"
99+ , \attrs child ->
100+ el attrs child
101+ )
102+ , ( "row"
103+ , \attrs child ->
104+ row attrs [ child ]
105+ )
106+ , ( "col"
107+ , \attrs child ->
108+ column attrs [ child ]
109+ )
110+ , ( "para"
111+ , \attrs child ->
112+ paragraph attrs [ child ]
113+ )
114+ , ( "txtCol"
115+ , \attrs child ->
116+ textColumn attrs [ child ]
117+ )
118+ ]
119+
120+
121+allElements =
122+ [ ( "el"
123+ , \attrs child ->
124+ el attrs child
125+ )
126+ , ( "row"
127+ , \attrs child ->
128+ row attrs [ child ]
129+ )
130+ , ( "col"
131+ , \attrs child ->
132+ column attrs [ child ]
133+ )
134+ , ( "para"
135+ , \attrs child ->
136+ paragraph attrs [ child ]
137+ )
138+ , ( "txtCol"
139+ , \attrs child ->
140+ textColumn attrs [ child ]
141+ )
142+ ]
143+
144+
145+allLayouts =
146+ [ ( "el"
147+ , \attrs child ->
148+ el attrs child
149+ )
150+ , ( "row 3, self 1"
151+ , \attrs child ->
152+ row attrs [ child, box, box ]
153+ )
154+ , ( "row 3, self 2"
155+ , \attrs child ->
156+ row attrs [ box, child, box ]
157+ )
158+ , ( "row 3, self 3"
159+ , \attrs child ->
160+ row attrs [ box, box, child ]
161+ )
162+ , ( "col 3, self 1"
163+ , \attrs child ->
164+ column attrs [ child, box, box ]
165+ )
166+ , ( "col 3, self 2"
167+ , \attrs child ->
168+ column attrs [ box, child, box ]
169+ )
170+ , ( "col 3, self 3"
171+ , \attrs child ->
172+ column attrs [ box, box, child ]
173+ )
174+ , ( "para"
175+ , \attrs child ->
176+ paragraph attrs [ child ]
177+ )
178+ , ( "txtCol"
179+ , \attrs child ->
180+ textColumn attrs [ child ]
181+ )
182+ ]
183+
184+
185+nearbys =
186+ [ ( "inFront", inFront )
187+ , ( "above", above )
188+ , ( "onLeft", onLeft )
189+ , ( "onRight", onRight )
190+ , ( "below", below )
191+ , ( "behindContent", behindContent )
192+ ]
193+
194+
195+alignments =
196+ horizontal ++ vertical
197+
198+
199+horizontal =
200+ [ Tuple.pair "alignLeft" alignLeft
201+ , Tuple.pair "alignRight" alignRight
202+ , Tuple.pair "centerX" centerX
203+ ]
204+
205+
206+vertical =
207+ [ Tuple.pair "alignTop" alignTop
208+ , Tuple.pair "alignBottom" alignBottom
209+ , Tuple.pair "centerY" centerY
210+ ]
211+
212+
213+extractLabel maybe =
214+ maybe
215+
216+
217+allAlignments =
218+ mapEveryCombo
219+ (\maybeOne maybeTwo ->
220+ let
221+ labels =
222+ List.filterMap (Maybe.map Tuple.first)
223+ [ maybeOne
224+ , maybeTwo
225+ ]
226+
227+ attrs =
228+ List.filterMap (Maybe.map Tuple.second)
229+ [ maybeOne
230+ , maybeTwo
231+ ]
232+ in
233+ Tuple.pair (String.join "++" labels)
234+ attrs
235+ )
236+ (Nothing :: List.map Just horizontal)
237+ (Nothing :: List.map Just vertical)
238+
239+
240+contents =
241+ [ ( "none", none )
242+ , ( "short text", text short )
243+
244+ -- , ( "long text", text lorem )
245+ , ( "box"
246+ , box
247+ )
248+ ]
249+
250+
251+box =
252+ el
253+ [ width (px 50)
254+ , height (px 50)
255+ , Background.color (rgb (240 / 255) 0 (245 / 255))
256+ , Font.color (rgb 1 1 1)
257+ ]
258+ none
259+
260+
261+short =
262+ "short and small"
263+
264+
265+lorem =
266+ "There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc."
267+
268+
269+mapEveryCombo fn listOne listTwo =
270+ List.concatMap
271+ (\one ->
272+ List.map
273+ (\two ->
274+ fn one two
275+ )
276+ listTwo
277+ )
278+ listOne
279+
280+
281+mapEveryCombo3 fn listOne listTwo listThree =
282+ List.concatMap
283+ (\one ->
284+ List.concatMap
285+ (\two ->
286+ List.map
287+ (\three ->
288+ fn one two three
289+ )
290+ listThree
291+ )
292+ listTwo
293+ )
294+ listOne
295+
296+
297+mapEveryCombo4 fn listOne listTwo listThree listFour =
298+ List.concatMap
299+ (\one ->
300+ List.concatMap
301+ (\two ->
302+ List.concatMap
303+ (\three ->
304+ List.map
305+ (\four ->
306+ fn one two three four
307+ )
308+ listFour
309+ )
310+ listThree
311+ )
312+ listTwo
313+ )
314+ listOne
315+
316+
317+sizes render =
318+ List.concatMap
319+ (\( widthLen, heightLen ) ->
320+ [ text (Debug.toString ( widthLen, heightLen ))
321+ , render
322+ (\attrs children ->
323+ el
324+ (width widthLen
325+ :: height heightLen
326+ :: attrs
327+ )
328+ children
329+ )
330+ ]
331+ )
332+ allLengthPairs
333+
334+
335+allLengthPairs : List ( Length, Length )
336+allLengthPairs =
337+ let
338+ crossProduct len =
339+ List.map (Tuple.pair len) lengths
340+ in
341+ List.concatMap crossProduct lengths
342+
343+
344+lengths =
345+ [ px 50
346+ , fill
347+ , shrink
348+ , fill
349+ |> maximum 100
350+ , fill
351+ |> maximum 100
352+ |> minimum 50
353+ , shrink
354+ |> maximum 100
355+ , shrink
356+ |> maximum 100
357+ |> minimum 50
358+ ]
359+
360+
361+type Generated thing
362+ = Generated (List (Labeled thing))
363+
364+
365+type alias Labeled thing =
366+ ( String, thing )
367+
368+
369+with : List (Labeled a) -> List (Labeled (a -> b)) -> List (Labeled b)
370+with first funcs =
371+ List.concatMap
372+ (\( lbl, fst ) ->
373+ List.map
374+ (\( fnLbl, fn ) ->
375+ Tuple.pair (fnLbl ++ "+" ++ lbl) (fn fst)
376+ )
377+ funcs
378+ )
379+ first
380+
381+
382+generate : String -> generated -> List (Labeled generated)
383+generate lbl fn =
384+ [ Tuple.pair lbl fn
385+ ]
386+
387+
388+test : List (Labeled (Testable.Element msg))
389+test =
390+ generate "Alignments"
391+ (\align ->
392+ el align none
393+ )
394+ |> with allAlignments
395+
396+
397+
398+-- |>
tests-rendering/src/Testable/Runner.elm+173−76
@@ -1,4 +1,12 @@
1−port module Testable.Runner exposing (Msg, TestableProgram, program, show)
1+port module Testable.Runner exposing
2+ ( Msg
3+ , Testable
4+ , TestableProgram
5+ , program
6+ , rename
7+ , show
8+ , testable
9+ )
2
10
3{-| -}
11{-| -}
4
12
@@ -26,6 +34,22 @@ type alias TestableProgram =
26 Program () (Model Msg) Msg
34 Program () (Model Msg) Msg
27
35
28
36
37+{-| This should be a real type, but I'm too busy atm.
38+-}
39+type alias Testable =
40+ ( String, Testable.Element Msg )
41+
42+
43+rename : String -> Testable -> Testable
44+rename newName ( _, el ) =
45+ ( newName, el )
46+
47+
48+testable : String -> Testable.Element Msg -> Testable
49+testable =
50+ Tuple.pair
51+
52+
29palette =
53palette =
30 { white = Element.rgb 1 1 1
54 { white = Element.rgb 1 1 1
31 , red = Element.rgb 1 0 0
55 , red = Element.rgb 1 0 0
@@ -35,7 +59,7 @@ palette =
35 }
59 }
36
60
37
61
38−program : List ( String, Testable.Element Msg ) -> TestableProgram
62+program : List Testable -> TestableProgram
39program tests =
63program tests =
40 let
64 let
41 ( current, upcoming ) =
65 ( current, upcoming ) =
@@ -52,10 +76,11 @@ program tests =
52 ( { current = current
76 ( { current = current
53 , upcoming = upcoming
77 , upcoming = upcoming
54 , finished = []
78 , finished = []
79+ , selected = 0
55 , highlightDomId = Nothing
80 , highlightDomId = Nothing
56 }
81 }
57 , Task.perform (always Analyze)
82 , Task.perform (always Analyze)
58− (Process.sleep 32
83+ (Process.sleep 64
59 |> Task.andThen
84 |> Task.andThen
60 (always Time.now)
85 (always Time.now)
61 )
86 )
@@ -77,12 +102,14 @@ type alias Model msg =
77 { current : Maybe ( String, Testable.Element msg )
102 { current : Maybe ( String, Testable.Element msg )
78 , upcoming : List ( String, Testable.Element msg )
103 , upcoming : List ( String, Testable.Element msg )
79 , finished : List (WithResults (Testable.Element msg))
104 , finished : List (WithResults (Testable.Element msg))
105+ , selected : Int
80 , highlightDomId : Maybe String
106 , highlightDomId : Maybe String
81 }
107 }
82
108
83
109
84type alias WithResults thing =
110type alias WithResults thing =
111+ { index : Int
85− { element : thing
112+ , element : thing
86 , label : String
113 , label : String
87 , results :
114 , results :
88 List Testable.LayoutTest
115 List Testable.LayoutTest
@@ -131,6 +158,7 @@ encodeForReport withResults =
131type Msg
158type Msg
132 = NoOp
159 = NoOp
133 | Analyze
160 | Analyze
161+ | Select Int
134 | HighlightDomID (Maybe String)
162 | HighlightDomID (Maybe String)
135 | RefreshBoundingBox
163 | RefreshBoundingBox
136 (List
164 (List
@@ -143,13 +171,14 @@ type Msg
143 )
171 )
144
172
145
173
146−runTest : Dict String Testable.Found -> String -> Testable.Element msg -> WithResults (Testable.Element msg)
174+runTest : Int -> Dict String Testable.Found -> String -> Testable.Element msg -> WithResults (Testable.Element msg)
147−runTest boxes label element =
175+runTest index boxes label element =
148 let
176 let
149 results =
177 results =
150 Testable.runTests boxes element
178 Testable.runTests boxes element
151 in
179 in
180+ { index = index
152− { element = element
181+ , element = element
153 , label = label
182 , label = label
154 , results = results
183 , results = results
155 }
184 }
@@ -166,6 +195,11 @@ update msg model =
166 , Cmd.none
195 , Cmd.none
167 )
196 )
168
197
198+ Select index ->
199+ ( { model | selected = index }
200+ , Cmd.none
201+ )
202+
169 RefreshBoundingBox boxes ->
203 RefreshBoundingBox boxes ->
170 case model.current of
204 case model.current of
171 Nothing ->
205 Nothing ->
@@ -190,7 +224,7 @@ update msg model =
190 |> Dict.fromList
224 |> Dict.fromList
191
225
192 currentResults =
226 currentResults =
193− runTest foundData label current
227+ runTest (List.length model.finished) foundData label current
194 in
228 in
195 case model.upcoming of
229 case model.upcoming of
196 [] ->
230 [] ->
@@ -208,7 +242,7 @@ update msg model =
208 , upcoming = remaining
242 , upcoming = remaining
209 }
243 }
210 , Task.perform (always Analyze)
244 , Task.perform (always Analyze)
211− (Process.sleep 32
245+ (Process.sleep 64
212 |> Task.andThen
246 |> Task.andThen
213 (always Time.now)
247 (always Time.now)
214 )
248 )
@@ -232,50 +266,61 @@ view model =
232 case model.current of
266 case model.current of
233 Nothing ->
267 Nothing ->
234 if List.isEmpty model.upcoming then
268 if List.isEmpty model.upcoming then
235− case model.finished of
269+ let
236− [] ->
270+ selected =
237− Element.layout [] <|
271+ getByIndex model.selected model.finished
238− Element.column
272+ in
239− [ Element.spacing 20
240− , Element.padding 20
241− , Element.width (Element.px 800)
242− ]
243− [ Element.none ]
244−
245− finished :: remaining ->
246− Element.layout
273+ Element.layout
247− [ Font.size 16
274+ [ Font.size 16
248− , Element.inFront (Element.html (viewElementHighlight model))
275+ , Element.inFront (Element.html (viewElementHighlight model))
276+ , Element.height Element.fill
277+ ]
278+ <|
279+ Element.row [ Element.width Element.fill, Element.height Element.fill ]
280+ [ Element.el
281+ [ Element.width
282+ (Element.fill
283+ |> Element.maximum 900
284+ )
285+ , Element.alignTop
286+ , Element.height Element.fill
287+ , Element.scrollbars
249 ]
288 ]
250− <|
251− Element.row [ Element.width Element.fill ]
252− [ Element.el
289+ (Element.el
253− [ Element.width Element.fill
290+ [ Element.centerX
254− ]
291+ , Element.padding 100
292+ , Border.dashed
293+ , Border.width 2
294+ , Border.color palette.lightGrey
295+ , Font.size 20
296+ , Element.inFront
255 (Element.el
297 (Element.el
256− [ Element.centerX
257− , Element.padding 100
258− , Border.dashed
259− , Border.width 2
260− , Border.color palette.lightGrey
261− , Font.size 20
262− , Element.inFront
263− (Element.el
264− [ Font.size 14
298+ [ Font.size 14
265− , Font.color palette.lightGrey
299+ , Font.color palette.lightGrey
266− ]
267− (Element.text "test case")
268− )
269 ]
300 ]
270− (Testable.toElement finished.element)
301+ (Element.text "test case")
271 )
302 )
272− , Element.column
273− [ Element.spacing 20
274− , Element.padding 20
275− , Element.width Element.fill
276− ]
277− (List.map viewResult (finished :: remaining))
278 ]
303 ]
304+ (case selected of
305+ Nothing ->
306+ Element.text "nothing selected"
307+
308+ Just sel ->
309+ Testable.toElement sel.element
310+ )
311+ )
312+ , Element.column
313+ [ Element.spacing 20
314+ , Element.padding 20
315+ , Element.width Element.fill
316+ , Element.height Element.fill
317+ , Element.scrollbarY
318+ ]
319+ (model.finished
320+ |> List.sortBy hasFailure
321+ |> List.map (viewResult model.selected)
322+ )
323+ ]
279
324
280 else
325 else
281 Html.text ""
326 Html.text ""
@@ -284,6 +329,20 @@ view model =
284 Testable.toHtml current
329 Testable.toHtml current
285
330
286
331
332+getByIndex i ls =
333+ List.foldl
334+ (\elem ( index, found ) ->
335+ if i == index then
336+ ( index + 1, Just elem )
337+
338+ else
339+ ( index + 1, found )
340+ )
341+ ( 0, Nothing )
342+ ls
343+ |> Tuple.second
344+
345+
287viewElementHighlight model =
346viewElementHighlight model =
288 case model.highlightDomId of
347 case model.highlightDomId of
289 Nothing ->
348 Nothing ->
@@ -292,7 +351,7 @@ viewElementHighlight model =
292 Just highlightDomId ->
351 Just highlightDomId ->
293 let
352 let
294 elementHighlight =
353 elementHighlight =
295− highlightDomId ++ " { outline: solid; }"
354+ highlightDomId ++ " { outline: solid black; }"
296
355
297 testId =
356 testId =
298 highlightDomId
357 highlightDomId
@@ -300,7 +359,7 @@ viewElementHighlight model =
300 |> String.append "#tests-"
359 |> String.append "#tests-"
301
360
302 testHighlight =
361 testHighlight =
303− testId ++ " { outline: dashed; }"
362+ testId ++ " { outline: dashed black; }"
304
363
305 styleSheet =
364 styleSheet =
306 String.join "\n"
365 String.join "\n"
@@ -314,35 +373,73 @@ viewElementHighlight model =
314 ]
373 ]
315
374
316
375
317−viewResult : WithResults (Testable.Element Msg) -> Element.Element Msg
376+hasFailure : WithResults (Testable.Element Msg) -> Int
318−viewResult testable =
377+hasFailure myTest =
319− let
378+ if
320− isExpectationPassing result =
379+ List.any
321− case result of
380+ (not << isPassing)
322− Testable.Todo label ->
381+ myTest.results
323− True
382+ then
383+ 0
324
384
325− Testable.Expect details ->
385+ else
326− details.result
386+ 1
327
387
328− isPassing layoutTest =
329− List.any isExpectationPassing layoutTest.expectations
330
388
331− ( passing, failing ) =
389+isExpectationPassing result =
332− List.partition isPassing testable.results
390+ case result of
333− in
391+ Testable.Todo label ->
392+ True
393+
394+ Testable.Expect details ->
395+ details.result
396+
397+
398+isPassing layoutTest =
399+ List.all isExpectationPassing layoutTest.expectations
400+
401+
402+viewResult : Int -> WithResults (Testable.Element Msg) -> Element.Element Msg
403+viewResult selectedIndex myTest =
404+ if myTest.index == selectedIndex then
334− Element.column
405+ Element.column
335− [ Element.alignLeft
406+ [ Element.alignLeft
336− , Element.spacing 16
407+ , Element.spacing 16
337− ]
408+ ]
338− [ Element.el [ Font.size 24 ] (Element.text testable.label)
409+ [ Element.el [ Font.size 24 ] (Element.text myTest.label)
339− , Element.column
410+ , Element.column
340− [ Element.alignLeft, Element.spacing 16 ]
411+ [ Element.alignLeft, Element.spacing 16 ]
341− (testable.results
412+ (myTest.results
342− |> groupBy .elementDomId
413+ |> groupBy .elementDomId
343− |> List.map (expandDetails >> viewLayoutTestGroup)
414+ |> List.map (expandDetails >> viewLayoutTestGroup)
344− )
415+ )
416+ ]
417+
418+ else
419+ let
420+ ( passing, failing ) =
421+ List.partition isPassing myTest.results
422+ in
423+ Element.column
424+ [ Element.alignLeft
425+ , Element.spacing 16
426+ , Element.pointer
427+ , Events.onClick (Select myTest.index)
428+ ]
429+ [ Element.row [ Element.spacing 16 ]
430+ [ Element.el [ Font.size 16 ] (Element.text myTest.label)
431+ , Element.text (String.fromInt (List.length passing) ++ " passing")
432+ , let
433+ failingCount =
434+ List.length failing
435+ in
436+ if failingCount == 0 then
437+ Element.none
438+
439+ else
440+ Element.text (String.fromInt (List.length failing) ++ " failing")
441+ ]
345− ]
442+ ]
346
443
347
444
348expandDetails group =
445expandDetails group =
tests-rendering/src/Tests/Alignment.elmnew file+49
@@ -0,0 +1,49 @@
1+module Tests.Alignment exposing (view)
2+
3+{-| Testing nearby elements such as those defined with `above`, `below`, etc.
4+-}
5+
6+import Testable
7+import Testable.Element exposing (..)
8+import Testable.Element.Background as Background
9+import Testable.Element.Font as Font
10+import Testable.Generator
11+import Tests.Palette as Palette exposing (..)
12+
13+
14+box attrs =
15+ el
16+ ([ width (px 50)
17+ , height (px 50)
18+ , Background.color blue
19+ ]
20+ ++ attrs
21+ )
22+ none
23+
24+
25+{-| -}
26+view : List ( String, Testable.Element msg )
27+view =
28+ List.concat
29+ [ Testable.Generator.generate "Alignments"
30+ (\layout element alignment ->
31+ layout
32+ [ width (px 800)
33+ , height (px 800)
34+ , Background.color lightGrey
35+ ]
36+ (element
37+ ([ width (px 200)
38+ , height (px 200)
39+ , Background.color red
40+ ]
41+ ++ alignment
42+ )
43+ none
44+ )
45+ )
46+ |> Testable.Generator.with Testable.Generator.allLayouts
47+ |> Testable.Generator.with Testable.Generator.allElements
48+ |> Testable.Generator.with Testable.Generator.allAlignments
49+ ]
tests-rendering/src/Tests/All.elmnew file+44
@@ -0,0 +1,44 @@
1+module Tests.All exposing (main)
2+
3+{-| -}
4+
5+import Layout.NestedParagraphs
6+import Layout.SafariBugIssue147
7+import Testable.Generator
8+import Testable.Runner
9+import Tests.Alignment
10+import Tests.Nearby
11+import Tests.Spacing
12+import Tests.TextWrapping
13+import Tests.Transparency
14+
15+
16+main : Testable.Runner.TestableProgram
17+main =
18+ (Testable.Runner.program << List.concat)
19+ [ Testable.Generator.elementInLayout "Basics" []
20+ , Tests.Nearby.view
21+ , Tests.Alignment.view
22+ , Tests.Spacing.view
23+
24+ -- [
25+ -- , Tuple.pair "Transparency" Tests.Transparency.view
26+ -- ]
27+ -- , [ Tuple.pair "Paragraph wrapping" Tests.TextWrapping.view
28+ -- ]
29+ , issues
30+ ]
31+
32+
33+issues =
34+ [ -- Testable.Runner.rename "Weird Centering" WeirdCentering.view
35+ -- , Testable.Runner.rename "Stacked scrolling columns height" StackedScrollingColumnsHeight.view
36+ -- ,
37+ Testable.Runner.rename "Safari bug issue147" Layout.SafariBugIssue147.view
38+ , Testable.Runner.rename "Nested paragraphs" Layout.NestedParagraphs.view
39+
40+ -- , Testable.Runner.rename "Issue 22, zIndex" Nearby.Issue22ZIndex.view
41+ -- , Testable.Runner.rename "inFrontIssue" Nearby.InFrontIssue.view
42+ -- , Testable.Runner.rename "El in fixed height column" ElInFixedHeightColumn.view
43+ -- , Testable.Runner.rename "Clipped el in fixed width column" ClippedElInFixedWidthColumn.view
44+ ]
tests-rendering/src/Tests/Basic.elmdeleted−54
@@ -1,54 +0,0 @@
1−module Tests.Basic exposing (view)
2−
3−{-| -}
4−
5−import Element as Actual
6−import Html
7−import Testable
8−import Testable.Element as Element exposing (..)
9−import Testable.Element.Background as Background
10−import Testable.Element.Font as Font
11−import Testable.Runner
12−import Tests.Palette as Palette
13−
14−
15−{-| -}
16−main : Html.Html msg
17−main =
18− Testable.Runner.show view
19−
20−
21−{-| -}
22−view : Testable.Element msg
23−view =
24− row [ spacing 50, alignTop ]
25− [ el
26− [ width (px 200)
27− , height (px 200)
28− , Background.color Palette.blue
29− , Font.color Palette.white
30− ]
31− (text "Hello!")
32− , el
33− [ width (px 200)
34− , height (px 200)
35− , Background.color Palette.blue
36− , Font.color Palette.white
37− ]
38− (text "Hello!")
39− , el
40− [ width (px 200)
41− , height (px 200)
42− , Background.color (Actual.rgba 0 0 1 1)
43− , Font.color Palette.white
44− , below
45− (el
46− [ Background.color Palette.grey
47− , width (px 50)
48− , height (px 50)
49− ]
50− none
51− )
52− ]
53− (text "Hello!")
54− ]
tests-rendering/src/Tests/ColumnAlignment.elmdeleted−176
@@ -1,176 +0,0 @@
1−module Tests.ColumnAlignment exposing (..)
2−
3−import Html
4−import Testable
5−import Testable.Element as Element exposing (..)
6−import Testable.Element.Background as Background
7−import Testable.Element.Font as Font
8−import Testable.Runner
9−import Tests.Palette as Palette exposing (..)
10−
11−
12−{-| -}
13−main : Html.Html msg
14−main =
15− Testable.Runner.show view
16−
17−
18−box attrs =
19− el
20− ([ width (px 50)
21− , height (px 50)
22− , Background.color blue
23− ]
24− ++ attrs
25− )
26− none
27−
28−
29−container =
30− el [ width (px 100), height (px 100) ]
31−
32−
33−view =
34− let
35− colContainer attrs children =
36− column ([ Background.color lightGrey, spacing 20, width (px 100), height (px 500) ] ++ attrs) children
37−
38− tallContainer attrs children =
39− column ([ Background.color lightGrey, spacing 20, width (px 100), height fill ] ++ attrs) children
40− in
41− column
42− [ width fill, spacing 20 ]
43− [ el [] (text "Alignment Within a Column")
44− , row [ spacing 20 ]
45− [ colContainer []
46− [ box [] ]
47− , colContainer []
48− [ box [ centerY ]
49− ]
50− , colContainer []
51− [ box [ alignBottom, label "first" ]
52− ]
53− ]
54− , row [ spacing 20 ]
55− [ colContainer []
56− [ box [] ]
57− , colContainer []
58− [ box []
59− , box []
60− , box []
61− ]
62− , colContainer []
63− [ box [ alignLeft, label "first" ]
64− , box [ centerX, label "second" ]
65− , box [ alignRight, label "third" ]
66− ]
67− ]
68− , row [ spacing 20 ]
69− [ colContainer []
70− [ box []
71− , box []
72− , box []
73− ]
74− , colContainer []
75− [ box []
76− , box []
77− , box [ alignBottom, label "third" ]
78− ]
79− , colContainer []
80− [ box []
81− , box [ alignBottom, label "second" ]
82− , box []
83− ]
84− , colContainer []
85− [ box [ alignBottom, label "first" ]
86− , box []
87− , box []
88− ]
89− ]
90− , text "centerY"
91− , row [ spacing 20 ]
92− [ colContainer [ height fill ]
93− [ box [ centerY, label "solo" ]
94− ]
95− , colContainer []
96− [ box []
97− , box [ centerY, label "middle" ]
98− , box []
99− ]
100− , colContainer []
101− [ box []
102− , box []
103− , box [ centerY, label "last" ]
104− ]
105− ]
106− , text "multiple centerY"
107− , row [ height (px 800), spacing 20 ]
108− [ tallContainer []
109− [ box []
110− , box [ centerY ]
111− , box [ centerY ]
112− , box [ centerY ]
113− , box [ centerY ]
114− , box [ alignBottom ]
115− ]
116− , tallContainer []
117− [ box []
118− , box [ centerY ]
119− , box []
120− ]
121− , tallContainer []
122− [ box []
123− , box []
124− , box [ centerY ]
125− ]
126− ]
127− , text "top, center, bottom"
128− , row [ spacing 20 ]
129− [ colContainer []
130− [ box [ alignTop, label "first" ]
131− , box []
132− , box [ alignBottom, label "last" ]
133− ]
134− , colContainer []
135− [ box [ alignTop ]
136− , box [ centerY ]
137− , box [ alignBottom ]
138− ]
139− , colContainer []
140− [ box [ alignLeft, alignTop ]
141− , box [ centerX, centerY ]
142− , box [ alignRight, alignBottom ]
143− ]
144− ]
145− , el [ width fill ] (text "Column in a Row")
146− , row [ width fill, spacing 20, label "row" ]
147− [ box [ alignLeft, alignTop, label "box" ]
148− , column
149− [ alignLeft
150− , alignTop
151− , spacing 20
152− , label "column"
153− , Background.color lightGrey
154− ]
155− [ box []
156− , box []
157− , box []
158− ]
159− , column
160− [ spacing 20
161− , width (px 100)
162− , alignLeft
163− , alignTop
164− , Background.color lightGrey
165− ]
166− [ box []
167− , box []
168− , box []
169− ]
170− , colContainer []
171− [ box [ alignRight ]
172− , box [ centerX ]
173− , box [ alignLeft ]
174− ]
175− ]
176− ]
tests-rendering/src/Tests/ColumnSpacing.elmdeleted−68
@@ -1,68 +0,0 @@
1−module Tests.ColumnSpacing exposing (..)
2−
3−import Html
4−import Testable
5−import Testable.Element as Element exposing (..)
6−import Testable.Element.Background as Background
7−import Testable.Element.Font as Font
8−import Testable.Runner
9−import Tests.Palette as Palette exposing (..)
10−
11−
12−{-| -}
13−main : Html.Html msg
14−main =
15− Testable.Runner.show view
16−
17−
18−box attrs =
19− el
20− ([ width (px 50)
21− , height (px 50)
22− , Background.color blue
23− ]
24− ++ attrs
25− )
26− none
27−
28−
29−tinyBox attrs =
30− el
31− ([ width (px 20)
32− , height (px 20)
33−
34− -- , centerY
35− , Background.color darkCharcoal
36− ]
37− ++ attrs
38− )
39− none
40−
41−
42−container =
43− el [ width (px 100), height (px 100) ]
44−
45−
46−view =
47− let
48− colContainer attrs children =
49− column ([ spacing 20, width (px 100), height (px 500) ] ++ attrs) children
50− in
51− column
52− []
53− [ el [] (text "Spacing within a column")
54− , row []
55− [ colContainer []
56− [ box [] ]
57− , colContainer []
58− [ box []
59− , box []
60− , box []
61− ]
62− , colContainer [ onRight (tinyBox []) ]
63− [ box []
64− , box []
65− , box []
66− ]
67− ]
68− ]
tests-rendering/src/Tests/ElementAlignment.elmdeleted−111
@@ -1,111 +0,0 @@
1−module Tests.ElementAlignment exposing (..)
2−
3−import Generator
4−import Html
5−import Testable
6−import Testable.Element as Element exposing (..)
7−import Testable.Element.Background as Background
8−import Testable.Element.Font as Font
9−import Testable.Runner
10−import Tests.Palette as Palette exposing (..)
11−
12−
13−{-| -}
14−main : Html.Html msg
15−main =
16− Testable.Runner.show view
17−
18−
19−box : List (Testable.Attr msg) -> Testable.Element msg
20−box attrs =
21− el
22− ([ width (px 50)
23− , height (px 50)
24− , Background.color blue
25− ]
26− ++ attrs
27− )
28− none
29−
30−
31−container : Testable.Element msg -> Testable.Element msg
32−container =
33− el
34− [ width (px 200)
35− , height (px 200)
36− , Background.color lightGrey
37− ]
38−
39−
40−view : Testable.Element msg
41−view =
42− column []
43− [ el [] (text "Alignment Within an El")
44− , container <|
45− box []
46− , text "alignLeft, centerX, alignRight"
47− , column [ spacing 20 ] <|
48− Generator.sizes
49− (\resizeable ->
50− row [ spacing 20 ]
51− [ container <|
52− resizeable [ Background.color blue, alignLeft ] none
53− , container <|
54− resizeable [ Background.color blue, centerX ] none
55− , container <|
56− resizeable [ Background.color blue, alignRight ] none
57− ]
58− )
59− , text "top, centerY, bottom"
60− , column [ spacing 20 ] <|
61− Generator.sizes
62− (\resizeable ->
63− row [ spacing 20 ]
64− [ container <|
65− resizeable [ alignTop ] none
66− , container <|
67− resizeable [ centerY ] none
68− , container <|
69− resizeable [ alignBottom ] none
70− ]
71− )
72− , text "align top ++ alignments"
73− , column [ spacing 20 ] <|
74− Generator.sizes
75− (\resizeable ->
76− row [ spacing 20 ]
77− [ container <|
78− resizeable [ alignTop, alignLeft ] none
79− , container <|
80− resizeable [ alignTop, centerX ] none
81− , container <|
82− resizeable [ alignTop, alignRight ] none
83− ]
84− )
85− , text "centerY ++ alignments"
86− , column [ spacing 20 ] <|
87− Generator.sizes
88− (\resizeable ->
89− row [ spacing 20 ]
90− [ container <|
91− resizeable [ centerY, alignLeft ] none
92− , container <|
93− resizeable [ centerY, centerX ] none
94− , container <|
95− resizeable [ centerY, alignRight ] none
96− ]
97− )
98− , text "alignBottom ++ alignments"
99− , column [ spacing 20 ] <|
100− Generator.sizes
101− (\resizeable ->
102− row [ spacing 20 ]
103− [ container <|
104− resizeable [ alignBottom, alignLeft ] none
105− , container <|
106− resizeable [ alignBottom, centerX ] none
107− , container <|
108− resizeable [ alignBottom, alignRight ] none
109− ]
110− )
111− ]
tests-rendering/src/Tests/Nearby.elm+97−356
@@ -8,6 +8,7 @@ import Testable
8import Testable.Element exposing (..)
8import Testable.Element exposing (..)
9import Testable.Element.Background as Background
9import Testable.Element.Background as Background
10import Testable.Element.Font as Font
10import Testable.Element.Font as Font
11+import Testable.Generator
11import Testable.Runner
12import Testable.Runner
12import Tests.Palette as Palette exposing (..)
13import Tests.Palette as Palette exposing (..)
13
14
@@ -57,365 +58,39 @@ p attrs =
57
58
58
59
59{-| -}
60{-| -}
60−main : Html.Html msg
61−main =
62− Testable.Runner.show view
63−
64−
65−{-| -}
66−view : Testable.Element msg
61+view : List ( String, Testable.Element msg )
67view =
62view =
68− let
63+ List.concat
69− transparentBox attrs =
64+ [ [ Tuple.pair "Parent inFront above child inFront" layeredVisibility
70− el
65+ , Tuple.pair "Sibling onLeft above sibling inFront" overlappingChildren
71− ([ Font.color white
66+ , Tuple.pair "el with all nearbys and alignments" master
72− , width (px 50)
67+ , Tuple.pair "paragraph with all nearbys and alignments" masterParagraph
73− , height (px 50)
68+ ]
74− , Background.color white
69+ , Testable.Generator.generate "Nearbys"
75− ]
70+ (\element nearby ->
76− ++ attrs
71+ element
77− )
78− (text "hi")
79−
80− -- single location name box =
81− -- row [ height (px 100), width fill, spacing 50 ]
82− -- [ box
83− -- [ location
84− -- (el
85− -- [ width (px 20)
86− -- , height (px 20)
87− -- , Background.color darkCharcoal
88− -- ]
89− -- none
90− -- )
91− -- ]
92− -- , box
72+ [ nearby (box [])
93− -- [ location
94− -- (el
95− -- [ width (px 20)
73+ , width (px 200)
96− -- , height (px 20)
74+ , height (px 200)
97− -- , alignLeft
98− -- , Background.color darkCharcoal
75+ , Background.color red
99− -- ]
100− -- none
101− -- )
102− -- ]
103− -- ]
104− little name attrs =
105− el
106− ([ label name
107− , width (px 5)
108− , height (px 5)
109− , Background.color darkCharcoal
110− ]
111− ++ attrs
112− )
113− none
114−
115− nearby location name render =
116− column [ spacing 32, label "column" ]
117− [ el [ padding 20, Background.color green, Font.color white ] (text name)
118− , row [ height (px 100), width fill, spacing 50 ]
119− [ render
120− [ location
121− (el
122− [ label name
123− , width (px 20)
124− , height (px 20)
125− , Background.color darkCharcoal
126− ]
127− none
128− )
129− ]
130− , render
131− [ location
132− (el
133− [ label name
134− , width (px 20)
135− , height (px 20)
136− , alignLeft
137− , Background.color darkCharcoal
138− ]
139− none
140− )
141− ]
142− , render
143− [ location
144− (el
145− [ label name
146− , width (px 20)
147− , height (px 20)
148− , centerX
149− , Background.color darkCharcoal
150− ]
151− none
152− )
153− ]
154− , render
155− [ location
156− (el
157− [ label name
158− , width (px 20)
159− , height (px 20)
160− , alignRight
161− , Background.color darkCharcoal
162− ]
163− none
164− )
165− ]
166− , render
167− [ location
168− (el
169− [ label name
170− , width (px 20)
171− , height (px 20)
172− , alignTop
173− , Background.color darkCharcoal
174− ]
175− none
176− )
177− ]
178− , render
179− [ location
180− (el
181− [ label name
182− , width (px 20)
183− , height (px 20)
184− , centerY
185− , Background.color darkCharcoal
186− ]
187− none
188− )
189− ]
190− , render
191− [ location
192− (el
193− [ label name
194− , width (px 20)
195− , height (px 20)
196− , alignBottom
197− , Background.color darkCharcoal
198− ]
199− none
200− )
201− ]
202− ]
203− , text "widths/heights"
204− , row [ height (px 100), width fill, spacing 50, label "Row" ]
205− [ render
206− [ location
207− (el
208− [ label name
209− , width fill
210− , height fill
211− , Background.color darkCharcoal
212− ]
213− none
214− )
215− ]
216− , render
217− [ location
218− (el
219− [ label name
220− , width (px 20)
221− , height fill
222− , Background.color darkCharcoal
223− ]
224− none
225− )
226− ]
227− , render
228− [ label "render"
229− , location
230− (el
231− [ label name
232− , width fill
233− , height (px 20)
234− , Background.color darkCharcoal
235− ]
236− none
237− )
238− ]
239− , render
240− [ location
241− (el
242− [ label name
243− , width (px 20)
244− , height shrink
245− , Background.color darkCharcoal
246− , Font.color white
247− ]
248− (text "h-shrink")
249− )
250− ]
251− , render
252− [ location
253− (el
254− [ label name
255− , width shrink
256− , height (px 20)
257− , Background.color darkCharcoal
258− , Font.color white
259− ]
260− (text "w-shrink")
261− )
262− ]
263 ]
76 ]
264− , text "on paragraph"
265− , row [ width fill, spacing 50, label "Row" ]
266− [ p
267− [ location
268− (el
269− [ label name
270− , width (px 20)
271− , height (px 20)
272− , Background.color darkCharcoal
273− ]
274− none
77+ none
275− )
78+ )
276− ]
79+ |> Testable.Generator.with Testable.Generator.allElements
277− , p
80+ |> Testable.Generator.with Testable.Generator.nearbys
278− [ location
81+ , Testable.Generator.generate "Nearbys with alignment"
279− (el
82+ (\element nearby align ->
280− [ label name
83+ element
281− , width (px 20)
84+ [ nearby (box [ align ])
282− , height (px 20)
283− , alignLeft
284− , Background.color darkCharcoal
285− ]
286− none
287− )
288− ]
289− , p
290− [ location
291− (el
292− [ label name
293− , width (px 20)
294− , height (px 20)
295− , centerX
296− , Background.color darkCharcoal
297− ]
298− none
299− )
300− ]
301− , p
302− [ location
303− (el
304− [ label name
305− , width (px 20)
306− , height (px 20)
307− , alignRight
308− , Background.color darkCharcoal
309− ]
310− none
311− )
312− ]
313− , p
314− [ location
315− (el
316− [ label name
317− , width (px 20)
318− , height (px 20)
319− , alignTop
320− , Background.color darkCharcoal
321− ]
322− none
323− )
324− ]
325− , p
326− [ location
327− (el
328− [ label name
329− , width (px 20)
330− , height (px 20)
331− , centerY
332− , Background.color darkCharcoal
333− ]
334− none
335− )
336− ]
337− , p
338− [ location
339− (el
340− [ label name
341− , width (px 20)
85+ , width (px 200)
342− , height (px 20)
86+ , height (px 200)
343− , alignBottom
344− , Background.color darkCharcoal
87+ , Background.color red
345− ]
346− none
347− )
348− ]
349 ]
88 ]
350− ]
89+ none
351−
90+ )
352− master =
91+ |> Testable.Generator.with Testable.Generator.allElements
353− el [ padding 20 ] <|
92+ |> Testable.Generator.with Testable.Generator.nearbys
354− box
93+ |> Testable.Generator.with Testable.Generator.alignments
355− [ above (little "above-left" [ alignLeft ])
356− , above (little "above-center" [ centerX ])
357− , above (little "above-right" [ alignRight ])
358− , below (little "below-left" [ alignLeft ])
359− , below (little "below-center" [ centerX ])
360− , below (little "below-right" [ alignRight ])
361− , onRight (little "onRight-left" [ alignTop ])
362− , onRight (little "onRight-center" [ centerY ])
363− , onRight (little "onRight-right" [ alignBottom ])
364− , onLeft (little "onLeft-left" [ alignTop ])
365− , onLeft (little "onLeft-center" [ centerY ])
366− , onLeft (little "onLeft-right" [ alignBottom ])
367− , inFront (little "infront-left-top" [ alignTop, alignLeft ])
368− , inFront (little "infront-center-top" [ alignTop, centerX ])
369− , inFront (little "infront-right-top" [ alignTop, alignRight ])
370− , inFront (little "infront-left-center" [ centerY, alignLeft ])
371− , inFront (little "infront-center-center" [ centerY, centerX ])
372− , inFront (little "infront-right-center" [ centerY, alignRight ])
373− , inFront (little "infront-left-bottom" [ alignBottom, alignLeft ])
374− , inFront (little "infront-center-bottom" [ alignBottom, centerX ])
375− , inFront (little "infront-right-bottom" [ alignBottom, alignRight ])
376− ]
377−
378− masterParagraph =
379− el [ padding 20 ] <|
380− p
381− [ above (little "above-left" [ alignLeft ])
382− , above (little "above-center" [ centerX ])
383− , above (little "above-right" [ alignRight ])
384− , below (little "below-left" [ alignLeft ])
385− , below (little "below-center" [ centerX ])
386− , below (little "below-right" [ alignRight ])
387− , onRight (little "onRight-left" [ alignTop ])
388− , onRight (little "onRight-center" [ centerY ])
389− , onRight (little "onRight-right" [ alignBottom ])
390− , onLeft (little "onLeft-left" [ alignTop ])
391− , onLeft (little "onLeft-center" [ centerY ])
392− , onLeft (little "onLeft-right" [ alignBottom ])
393− , inFront (little "infront-left-top" [ alignTop, alignLeft ])
394− , inFront (little "infront-center-top" [ alignTop, centerX ])
395− , inFront (little "infront-right-top" [ alignTop, alignRight ])
396− , inFront (little "infront-left-center" [ centerY, alignLeft ])
397− , inFront (little "infront-center-center" [ centerY, centerX ])
398− , inFront (little "infront-right-center" [ centerY, alignRight ])
399− , inFront (little "infront-left-bottom" [ alignBottom, alignLeft ])
400− , inFront (little "infront-center-bottom" [ alignBottom, centerX ])
401− , inFront (little "infront-right-bottom" [ alignBottom, alignRight ])
402− ]
403− in
404− column
405− [ centerX, label "Nearby Elements", spacing 100 ]
406− [ layeredVisibility
407− , overlappingChildren
408−
409− -- Note: visibility checks like the above
410− -- need to be at the top so they're in the viewport
411− , master
412− , masterParagraph
413− , nearby above "above" box
414− , nearby below "below" box
415− , nearby inFront "inFront" box
416− , nearby onRight "onRight" box
417− , nearby onLeft "onLeft" box
418− , nearby behindContent "behindContent" transparentBox
419 ]
94 ]
420
95
421
96
@@ -436,3 +111,69 @@ overlappingChildren =
436 , el [ onLeft (littleBox "overlapping" [ isVisible, Background.color red ]) ]
111 , el [ onLeft (littleBox "overlapping" [ isVisible, Background.color red ]) ]
437 (justBox 40 darkGrey [])
112 (justBox 40 darkGrey [])
438 ]
113 ]
114+
115+
116+little name attrs =
117+ el
118+ ([ label name
119+ , width (px 5)
120+ , height (px 5)
121+ , Background.color darkCharcoal
122+ ]
123+ ++ attrs
124+ )
125+ none
126+
127+
128+master =
129+ el [ padding 20 ] <|
130+ box
131+ [ above (little "above-left" [ alignLeft ])
132+ , above (little "above-center" [ centerX ])
133+ , above (little "above-right" [ alignRight ])
134+ , below (little "below-left" [ alignLeft ])
135+ , below (little "below-center" [ centerX ])
136+ , below (little "below-right" [ alignRight ])
137+ , onRight (little "onRight-left" [ alignTop ])
138+ , onRight (little "onRight-center" [ centerY ])
139+ , onRight (little "onRight-right" [ alignBottom ])
140+ , onLeft (little "onLeft-left" [ alignTop ])
141+ , onLeft (little "onLeft-center" [ centerY ])
142+ , onLeft (little "onLeft-right" [ alignBottom ])
143+ , inFront (little "infront-left-top" [ alignTop, alignLeft ])
144+ , inFront (little "infront-center-top" [ alignTop, centerX ])
145+ , inFront (little "infront-right-top" [ alignTop, alignRight ])
146+ , inFront (little "infront-left-center" [ centerY, alignLeft ])
147+ , inFront (little "infront-center-center" [ centerY, centerX ])
148+ , inFront (little "infront-right-center" [ centerY, alignRight ])
149+ , inFront (little "infront-left-bottom" [ alignBottom, alignLeft ])
150+ , inFront (little "infront-center-bottom" [ alignBottom, centerX ])
151+ , inFront (little "infront-right-bottom" [ alignBottom, alignRight ])
152+ ]
153+
154+
155+masterParagraph =
156+ el [ padding 20 ] <|
157+ p
158+ [ above (little "above-left" [ alignLeft ])
159+ , above (little "above-center" [ centerX ])
160+ , above (little "above-right" [ alignRight ])
161+ , below (little "below-left" [ alignLeft ])
162+ , below (little "below-center" [ centerX ])
163+ , below (little "below-right" [ alignRight ])
164+ , onRight (little "onRight-left" [ alignTop ])
165+ , onRight (little "onRight-center" [ centerY ])
166+ , onRight (little "onRight-right" [ alignBottom ])
167+ , onLeft (little "onLeft-left" [ alignTop ])
168+ , onLeft (little "onLeft-center" [ centerY ])
169+ , onLeft (little "onLeft-right" [ alignBottom ])
170+ , inFront (little "infront-left-top" [ alignTop, alignLeft ])
171+ , inFront (little "infront-center-top" [ alignTop, centerX ])
172+ , inFront (little "infront-right-top" [ alignTop, alignRight ])
173+ , inFront (little "infront-left-center" [ centerY, alignLeft ])
174+ , inFront (little "infront-center-center" [ centerY, centerX ])
175+ , inFront (little "infront-right-center" [ centerY, alignRight ])
176+ , inFront (little "infront-left-bottom" [ alignBottom, alignLeft ])
177+ , inFront (little "infront-center-bottom" [ alignBottom, centerX ])
178+ , inFront (little "infront-right-bottom" [ alignBottom, alignRight ])
179+ ]
tests-rendering/src/Tests/RowAlignment.elmdeleted−212
@@ -1,212 +0,0 @@
1−module Tests.RowAlignment exposing (..)
2−
3−import Generator
4−import Html
5−import Testable
6−import Testable.Element as Element exposing (..)
7−import Testable.Element.Background as Background
8−import Testable.Element.Font as Font
9−import Testable.Runner
10−import Tests.Palette as Palette exposing (..)
11−
12−
13−{-| -}
14−main : Html.Html msg
15−main =
16− Testable.Runner.show view
17−
18−
19−box attrs =
20− el
21− ([ width (px 50)
22− , height (px 50)
23− , Background.color blue
24− ]
25− ++ attrs
26− )
27− none
28−
29−
30−view =
31− let
32− rowContainer attrs children =
33− row
34− ([ spacing 20
35− , height (px 100)
36− , Background.color lightGrey
37− ]
38− ++ attrs
39− )
40− children
41− in
42− column [ width (px 500), spacing 20 ]
43− [ el [] (text "Alignment Within a Row")
44− , column [ spacing 20 ] <|
45− Generator.sizes <|
46− \resizeable ->
47− rowContainer
48− [ label "single child" ]
49− [ resizeable [] none ]
50− , column [ spacing 20 ] <|
51− Generator.sizes <|
52− \resizeable ->
53− rowContainer
54− [ label "single child" ]
55− [ resizeable [ centerX ] none ]
56− , column [ spacing 20 ] <|
57− Generator.sizes <|
58− \resizeable ->
59− rowContainer [ label "single child" ]
60− [ resizeable [ alignRight ] none ]
61− , column [ spacing 20 ] <|
62− Generator.sizes <|
63− \resizeable ->
64− rowContainer []
65− [ resizeable [] none
66− , resizeable [] none
67− , resizeable [] none
68− ]
69− , column [ spacing 20 ] <|
70− Generator.sizes <|
71− \resizeable ->
72− rowContainer []
73− [ resizeable [] none
74− , resizeable [] none
75− , resizeable [ alignRight, label "Right Child in Row" ] none
76− ]
77− , column [ spacing 20 ] <|
78− Generator.sizes <|
79− \resizeable ->
80− rowContainer
81− []
82− [ resizeable [] none
83− , resizeable [ alignRight, label "Middle Child in Row" ] none
84− , resizeable [] none
85− ]
86− , column [ spacing 20 ] <|
87− Generator.sizes <|
88− \resizeable ->
89− rowContainer []
90− [ resizeable [ alignRight, label "Left Child in Row" ] none
91− , resizeable [] none
92− , resizeable [] none
93− ]
94− , text "center X"
95− , column [ spacing 20 ] <|
96− Generator.sizes <|
97− \resizeable ->
98− rowContainer []
99− [ resizeable [ centerX, label "Left Child in Row" ] none
100− , resizeable [] none
101− , resizeable [] none
102− ]
103− , column [ spacing 20 ] <|
104− Generator.sizes <|
105− \resizeable ->
106− rowContainer []
107− [ resizeable [] none
108− , resizeable [ centerX, label "Middle Child in Row" ] none
109− , resizeable [] none
110− ]
111− , column [ spacing 20 ] <|
112− Generator.sizes <|
113− \resizeable ->
114− rowContainer []
115− [ resizeable [] none
116− , resizeable [] none
117− , resizeable [ centerX, label "Right Child in Row" ] none
118− ]
119− , column [ spacing 20 ] <|
120− Generator.sizes <|
121− \resizeable ->
122− rowContainer []
123− [ resizeable [] none
124− , resizeable [] none
125− , resizeable [ centerX, label "Middle-Right Child in Row" ] none
126− , resizeable [] none
127− ]
128− , column [ spacing 20 ] <|
129− Generator.sizes <|
130− \resizeable ->
131− rowContainer []
132− [ resizeable [] none
133− , resizeable [] none
134− , resizeable [ centerX, label "Middle-Right Child in Row" ] none
135− , resizeable [ centerX, label "Middle-Right Child in Row" ] none
136− , resizeable [] none
137− ]
138− , column [ spacing 20 ] <|
139− Generator.sizes <|
140− \resizeable ->
141− rowContainer []
142− [ resizeable [] none
143− , resizeable [] none
144− , resizeable [ centerX, label "Middle-Right Child in Row" ] none
145− , resizeable [ centerX, label "Middle-Right Child in Row" ] none
146− , resizeable [ centerX, label "Middle-Right Child in Row" ] none
147− , resizeable [] none
148− ]
149− , text "left x right"
150− , column [ spacing 20 ] <|
151− Generator.sizes <|
152− \resizeable ->
153− rowContainer []
154− [ resizeable [ alignLeft, label "Left Child in Row" ] none
155− , resizeable [] none
156− , resizeable [ alignRight, label "Right Child in Row" ] none
157− ]
158− , text "left center right"
159− , column [ spacing 20 ] <|
160− Generator.sizes <|
161− \resizeable ->
162− rowContainer []
163− [ resizeable [ alignLeft, label "Left Child in Row" ] none
164− , resizeable [ centerX, label "Middle Child in Row" ] none
165− , resizeable [ alignRight, label "Right Child in Row" ] none
166− ]
167− , text "vertical alignment"
168− , column [ spacing 20 ] <|
169− Generator.sizes <|
170− \resizeable ->
171− rowContainer []
172− [ resizeable [ alignTop, label "Left Child in Row" ] none
173− , resizeable [ centerY, label "Middle Child in Row" ] none
174− , resizeable [ alignBottom, label "Right Child in Row" ] none
175− ]
176− , text "x and y alignments"
177− , column [ spacing 20 ] <|
178− Generator.sizes <|
179− \resizeable ->
180− rowContainer []
181− [ resizeable [ alignLeft, alignTop, label "Left Child" ] none
182− , resizeable [ centerX, centerY, label "Middle Child" ] none
183− , resizeable [ alignRight, alignBottom, label "Right Child" ] none
184− ]
185− , text "align Top and X alignments "
186− , column [ spacing 20 ] <|
187− Generator.sizes <|
188− \resizeable ->
189− rowContainer []
190− [ resizeable [ alignLeft, alignTop, label "Left Child" ] none
191− , resizeable [ centerX, alignTop, label "Middle Child" ] none
192− , resizeable [ alignRight, alignTop, label "Right Child" ] none
193− ]
194− , text "align Bottom and X alignments "
195− , column [ spacing 20 ] <|
196− Generator.sizes <|
197− \resizeable ->
198− rowContainer []
199− [ resizeable [ alignLeft, alignBottom, label "Left Child" ] none
200− , resizeable [ centerX, alignBottom, label "Middle Child" ] none
201− , resizeable [ alignRight, alignBottom, label "Right Child" ] none
202− ]
203− , text "centerY and X alignments "
204− , column [ spacing 20 ] <|
205− Generator.sizes <|
206− \resizeable ->
207− rowContainer []
208− [ resizeable [ alignLeft, centerY, label "Left Child" ] none
209− , resizeable [ centerX, centerY, label "Middle Child" ] none
210− , resizeable [ alignRight, centerY, label "Right Child" ] none
211− ]
212− ]
tests-rendering/src/Tests/RowSpacing.elmdeleted−69
@@ -1,69 +0,0 @@
1−module Tests.RowSpacing exposing (..)
2−
3−import Html
4−import Testable
5−import Testable.Element as Element exposing (..)
6−import Testable.Element.Background as Background
7−import Testable.Element.Font as Font
8−import Testable.Runner
9−import Tests.Palette as Palette exposing (..)
10−
11−
12−{-| -}
13−main : Html.Html msg
14−main =
15− Testable.Runner.show view
16−
17−
18−box attrs =
19− el
20− ([ width (px 50)
21− , height (px 50)
22− , Background.color blue
23− ]
24− ++ attrs
25− )
26− none
27−
28−
29−tinyBox attrs =
30− el
31− ([ width (px 20)
32− , height (px 20)
33−
34− -- , centerY
35− , Background.color darkCharcoal
36− ]
37− ++ attrs
38− )
39− none
40−
41−
42−container =
43− el [ width (px 100), height (px 100) ]
44−
45−
46−view =
47− let
48− colContainer attrs children =
49− row ([ spacing 20, width (px 500), height (px 120) ] ++ attrs) children
50− in
51− column
52− []
53− [ el [] (text "Spacing within a row")
54− , column []
55− [ box []
56− , colContainer []
57− [ box [] ]
58− , colContainer []
59− [ box []
60− , box []
61− , box []
62− ]
63− , colContainer [ below (tinyBox []) ]
64− [ box []
65− , box []
66− , box []
67− ]
68− ]
69− ]
tests-rendering/src/Tests/Run.elm+5−20
@@ -1,29 +1,14 @@
1module Tests.Run exposing (main)
1module Tests.Run exposing (main)
2
2
3+{-| _NOTE_ this is auto-generated! Notouchy!
3−{-| -}
4+-}
4
5
6+import ElInFixedHeightColumn
5import Testable.Runner
7import Testable.Runner
6−import Tests.Basic
7−import Tests.ColumnAlignment
8−import Tests.ColumnSpacing
9−import Tests.ElementAlignment
10−import Tests.Nearby
11−import Tests.RowAlignment
12−import Tests.RowSpacing
13−import Tests.Transparency
14
8
15
9
16main : Testable.Runner.TestableProgram
10main : Testable.Runner.TestableProgram
17main =
11main =
18− Testable.Runner.program
12+ Testable.Runner.program
19− [ Tuple.pair "Basic Element" Tests.Basic.view
13+ [ Testable.Runner.rename " El In Fixed Height Column" ElInFixedHeightColumn.view
20− , Tuple.pair "Nearby" Tests.Nearby.view
21− , Tuple.pair "Element Alignment" Tests.ElementAlignment.view
22− , Tuple.pair "Transparency" Tests.Transparency.view
23− , Tuple.pair "Column Alignment" Tests.ColumnAlignment.view
24−
25− -- This has 12k cases, so it runs slow and sometimes crashes IE
26− , Tuple.pair "Row Alignment" Tests.RowAlignment.view
27− , Tuple.pair "Column Spacing" Tests.ColumnSpacing.view
28− , Tuple.pair "Row Spacing" Tests.RowSpacing.view
29 ]
14 ]
tests-rendering/src/Tests/Spacing.elmnew file+36
@@ -0,0 +1,36 @@
1+module Tests.Spacing exposing (view)
2+
3+{-| Test that spacing works
4+-}
5+
6+import Testable
7+import Testable.Element exposing (..)
8+import Testable.Element.Background as Background
9+import Testable.Element.Font as Font
10+import Testable.Generator
11+import Tests.Palette as Palette exposing (..)
12+
13+
14+{-| -}
15+view : List ( String, Testable.Element msg )
16+view =
17+ List.concat
18+ [ Testable.Generator.generate "Spacing"
19+ (\layout element ->
20+ layout
21+ [ width (px 800)
22+ , height (px 800)
23+ , Background.color lightGrey
24+ , spacing 20
25+ ]
26+ (element
27+ [ width (px 200)
28+ , height (px 200)
29+ , Background.color red
30+ ]
31+ none
32+ )
33+ )
34+ |> Testable.Generator.with Testable.Generator.allLayouts
35+ |> Testable.Generator.with Testable.Generator.allElements
36+ ]
tests-rendering/src/Tests/TextWrapping.elmnew file+51
@@ -0,0 +1,51 @@
1+module Tests.TextWrapping exposing (main, view)
2+
3+import Html
4+import Testable
5+import Testable.Element exposing (..)
6+import Testable.Element.Background as Background
7+import Testable.Element.Font as Font
8+import Testable.Generator
9+import Testable.Runner
10+import Tests.Palette as Palette exposing (..)
11+
12+
13+box attrs =
14+ el
15+ ([ width (px 50)
16+ , height (px 50)
17+ , Background.color blue
18+ ]
19+ ++ attrs
20+ )
21+ none
22+
23+
24+{-| -}
25+main : Html.Html msg
26+main =
27+ Testable.Runner.show view
28+
29+
30+view =
31+ el [] <|
32+ paragraph []
33+ [ Testable.Generator.box
34+ ]
35+
36+
37+
38+-- column [ spacing 16 ]
39+-- [ paragraph []
40+-- [ el [] (text Testable.Generator.short)
41+-- ]
42+-- -- , paragraph []
43+-- -- [ text Testable.Generator.lorem
44+-- -- , text Testable.Generator.lorem
45+-- -- ]
46+-- -- , paragraph []
47+-- -- [ text Testable.Generator.lorem
48+-- -- , paragraph []
49+-- -- [ text Testable.Generator.lorem ]
50+-- -- ]
51+-- ]
tests-rendering/view/view.htmldeleted−174
@@ -1,174 +0,0 @@
1−<!DOCTYPE html>
2−<html>
3− <head>
4− <meta charset="UTF-8" />
5− <title>Rendering Benchmark Viewer</title>
6− <script type="text/javascript" src="./elm.js"></script>
7− </head>
8− <style></style>
9− <body id="root">
10− <div id="elm-home"></div>
11− <canvas id="canvas"></canvas>
12− </body>
13−
14− <script type="text/javascript">
15− // Calculations for canvas
16− var PIXEL_RATIO = (function () {
17− var ctx = document.createElement("canvas").getContext("2d"),
18− dpr = window.devicePixelRatio || 1,
19− bsr =
20− ctx.webkitBackingStorePixelRatio ||
21− ctx.mozBackingStorePixelRatio ||
22− ctx.msBackingStorePixelRatio ||
23− ctx.oBackingStorePixelRatio ||
24− ctx.backingStorePixelRatio ||
25− 1;
26−
27− return dpr / bsr;
28− })();
29−
30− function createHiDPICanvas(w, h, id, ratio) {
31− if (!ratio) {
32− ratio = PIXEL_RATIO;
33− }
34− let can = document.getElementById(id);
35− can.width = w * ratio;
36− can.height = h * ratio;
37− can.style.width = w + "px";
38− can.style.height = h + "px";
39− can.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0);
40− return can;
41− }
42− // create a canvas for text measurements
43− let canvas = createHiDPICanvas(200, 100, "canvas");
44− // Starting Elm App,
45− var app = Elm.WeirdCentering.init({
46− node: document.getElementById("elm-home"),
47− });
48−
49− var test_results = "waiting..";
50−
51− app.ports.report.subscribe(function (results) {
52− test_results = results;
53− });
54−
55− app.ports.analyze.subscribe(function (ids) {
56− // ids : List String
57− var idsLength = ids.length;
58− var results = [];
59− for (var i = 0; i < idsLength; i++) {
60− var id = ids[i];
61− var element = document.getElementById(id);
62− if (element == null) {
63− console.log("id " + id + " not found");
64− }
65− var style = getStyle(element);
66− var bbox = getBoundingBox(element);
67− var metrics = getTextMetrics(element);
68−
69− var visible = isVisible(id, bbox);
70−
71− var result = {
72− textMetrics: metrics,
73− bbox: bbox,
74− style: style,
75− id: id,
76− isVisible: visible,
77− };
78− results.push(result);
79− }
80− app.ports.styles.send(results);
81− });
82−
83− function isVisible(id, bbox) {
84− var current = document.getElementById(id);
85− var result = 0;
86− if (current == document.elementFromPoint(bbox["left"], bbox["top"])) {
87− result++;
88− }
89− if (
90− current == document.elementFromPoint(bbox["left"], bbox["bottom"] - 1)
91− ) {
92− result++;
93− }
94− if (
95− current == document.elementFromPoint(bbox["right"] - 1, bbox["top"])
96− ) {
97− result++;
98− }
99− if (
100− current ==
101− document.elementFromPoint(bbox["right"] - 1, bbox["bottom"] - 1)
102− ) {
103− result++;
104− }
105−
106− if (result == 4) {
107− return true;
108− } else {
109− return false;
110− }
111− }
112−
113− function getStyle(element) {
114− var props = [];
115− var style = window.getComputedStyle(element);
116− for (var i = style.length; i--; ) {
117− var name = style.item(i);
118− var value = style.getPropertyValue(name);
119− props.push([name, value]);
120− }
121− return props;
122− }
123−
124− function getBoundingBox(element) {
125− var bbox = element.getBoundingClientRect();
126− var style = window.getComputedStyle(element, null);
127−
128− var padding = {
129− top: parseFloat(style.getPropertyValue("padding-top")),
130− bottom: parseFloat(style.getPropertyValue("padding-bottom")),
131− left: parseFloat(style.getPropertyValue("padding-left")),
132− right: parseFloat(style.getPropertyValue("padding-right")),
133− };
134−
135− return {
136− top: bbox.top,
137− bottom: bbox.bottom,
138− left: bbox.left,
139− right: bbox.right,
140− width: bbox.width,
141− height: bbox.height,
142− padding: padding,
143− };
144− }
145− function getTextMetrics(element) {
146− // Given our element, we want to return the text metrics on the text within.
147− // If it is an element we want to measure:
148− // we want to get the font family
149− // and the font size.
150− // We're going to presume that the font is loaded.
151− let childrenTextMetrics = [];
152− for (i = 0; i < element.children.length; i++) {
153− if (element.children[i].classList.contains("t")) {
154− let style = window.getComputedStyle(element, null);
155− let fontSize = style.getPropertyValue("font-size");
156− let fontFamily = style.getPropertyValue("font-family");
157− let ctx = canvas.getContext("2d");
158−
159− ctx.font = fontSize + " " + fontFamily; //"16px Roboto";
160− let text = ctx.measureText(element.children[i].innerText);
161−
162− childrenTextMetrics.push({
163− actualBoundingBoxAscent: text.actualBoundingBoxAscent,
164− actualBoundingBoxDescent: text.actualBoundingBoxDescent,
165− actualBoundingBoxLeft: text.actualBoundingBoxLeft,
166− actualBoundingBoxRight: text.actualBoundingBoxRight,
167− width: text.width,
168− });
169− }
170− }
171− return childrenTextMetrics;
172− }
173− </script>
174−</html>