git.iko.soy/gigawork-coworking/gigawork-coworking.github.io
on master help sign in
Initial website
commit09b50fa060c40c41f3c4b6172f412f1073913164 authoriko <mail@iko.soy> dateTue 31 Dec 2024, 11:17 (2 years ago) parent42cb2ae
176 files changed+31327−10
app/Route/Index.elm+418−4 app/Shared.elm+2−1 deps/elm-ui/.github/ISSUE_TEMPLATE/bug-unexpected-behavior-report.md+21 deps/elm-ui/.github/workflows/docs-preview.yml+36 deps/elm-ui/.github/workflows/label-issues-from-body.yml+14 deps/elm-ui/.github/workflows/label-issues-from-comments.yml+59 deps/elm-ui/.github/workflows/tests.yml+43 deps/elm-ui/.gitignore+28 deps/elm-ui/CONTRIBUTING.md+25 deps/elm-ui/CSS-LOOKUP.md+18 deps/elm-ui/LICENSE+27 deps/elm-ui/README.md+77 deps/elm-ui/benchmarks/elm.json+34 deps/elm-ui/benchmarks/micro/Suite.elm+330 deps/elm-ui/benchmarks/micro/elm.json+30 deps/elm-ui/benchmarks/runtime/benchPage.js+146 deps/elm-ui/benchmarks/runtime/index.js+176 deps/elm-ui/benchmarks/runtime/template/run.html+57 deps/elm-ui/benchmarks/runtime/template/viewResults.html+24 deps/elm-ui/benchmarks/src/Baseline.elm+31 deps/elm-ui/benchmarks/src/Benchmark/Render.elm+148 deps/elm-ui/benchmarks/src/Contain.elm+159 deps/elm-ui/benchmarks/src/ManyElements.elm+516 deps/elm-ui/benchmarks/src/View/Results.elm+379 deps/elm-ui/elm.json+28 deps/elm-ui/examples/Basic.elm+29 deps/elm-ui/examples/Form.elm+209 deps/elm-ui/examples/Pseudo.elm+31 deps/elm-ui/examples/Table.elm+65 deps/elm-ui/examples/elm.json+22 deps/elm-ui/experiments/Accumulator.elm+57 deps/elm-ui/experiments/font-adjustment-updated/FontAdjustment.elm+545 deps/elm-ui/experiments/font-adjustment-updated/elm.json+25 deps/elm-ui/experiments/font-adjustment/FontAdjustment.elm+365 deps/elm-ui/experiments/font-adjustment/elm.json+25 deps/elm-ui/experiments/masks/Test.elm+10 deps/elm-ui/experiments/masks/elm.json+27 deps/elm-ui/experiments/masks/src/MaskedInput.elm+130 deps/elm-ui/experiments/masks/src/Notes.elm+189 deps/elm-ui/experiments/palette/PaletteTest.elm+37 deps/elm-ui/experiments/palette/elm.json+27 deps/elm-ui/experiments/palette/src/Palette.elm+214 deps/elm-ui/experiments/virtual-css/Main.elm+46 deps/elm-ui/experiments/virtual-css/Makefile+1 deps/elm-ui/experiments/virtual-css/cssom.js+47 deps/elm-ui/experiments/virtual-css/elm.json+25 deps/elm-ui/experiments/virtual-css/test.html+18 deps/elm-ui/experiments/workspace/Basic.elm+233 deps/elm-ui/experiments/workspace/Form.elm+234 deps/elm-ui/experiments/workspace/Scrollbars.elm+204 deps/elm-ui/experiments/workspace/Table.elm+65 deps/elm-ui/experiments/workspace/elm.json+25 deps/elm-ui/notes/BENCHMARKS.md+20 deps/elm-ui/notes/CHANGES-FROM-STYLE-ELEMENTS.md+199 deps/elm-ui/notes/RUNNING_TESTS.md+65 deps/elm-ui/notes/classifying-issues.md+29 deps/elm-ui/notes/discussion/ColorWithoutAlpha.API.md+135 deps/elm-ui/notes/discussion/ColorWithoutAlpha.md+67 deps/elm-ui/notes/discussion/Internationalization.md+13 deps/elm-ui/notes/discussion/PaletteGroups.md+132 deps/elm-ui/notes/implementation/NEARBY.md+24 deps/elm-ui/notes/research/Accessiblity.md+9 deps/elm-ui/notes/research/Compatibility-Android.md+12 deps/elm-ui/notes/research/Compatibility-iOS.md+12 deps/elm-ui/notes/research/Internationalization.md+10 deps/elm-ui/package-lock.json+1235 deps/elm-ui/package.json+34 deps/elm-ui/src/Element.elm+1686 deps/elm-ui/src/Element/Background.elm+226 deps/elm-ui/src/Element/Border.elm+281 deps/elm-ui/src/Element/Events.elm+265 deps/elm-ui/src/Element/Font.elm+525 deps/elm-ui/src/Element/Input.elm+2265 deps/elm-ui/src/Element/Keyed.elm+70 deps/elm-ui/src/Element/Lazy.elm+117 deps/elm-ui/src/Element/Region.elm+111 deps/elm-ui/src/Internal/Flag.elm+325 deps/elm-ui/src/Internal/Grid.elm+270 deps/elm-ui/src/Internal/Model.elm+3564 deps/elm-ui/src/Internal/Style.elm+1798 deps/elm-ui/tests-rendering/automation/build.js+90 deps/elm-ui/tests-rendering/automation/doc-preview.sh+1 deps/elm-ui/tests-rendering/automation/publish-file.sh+31 deps/elm-ui/tests-rendering/automation/run.js+304 deps/elm-ui/tests-rendering/automation/templates/Run.elm+14 deps/elm-ui/tests-rendering/automation/templates/gather-styles.html+185 deps/elm-ui/tests-rendering/automation/view.js+73 deps/elm-ui/tests-rendering/cases/Manual/AlignedForm.elm+286 deps/elm-ui/tests-rendering/cases/Manual/All.elm+1263 deps/elm-ui/tests-rendering/cases/Manual/LazyPerformance.elm+523 deps/elm-ui/tests-rendering/cases/Manual/OtherScrollbars.elm+36 deps/elm-ui/tests-rendering/cases/Manual/Overflow.elm+16 deps/elm-ui/tests-rendering/cases/Manual/Scrollbars.elm+62 deps/elm-ui/tests-rendering/cases/Manual/ScrollbarsPls.elm+58 deps/elm-ui/tests-rendering/cases/Manual/TextLayout.elm+43 deps/elm-ui/tests-rendering/cases/elm.json+23 deps/elm-ui/tests-rendering/cases/open/InFrontSize.elm+43 deps/elm-ui/tests-rendering/cases/open/LabelledInputAlignRight.elm+28 deps/elm-ui/tests-rendering/cases/open/NearbyElementBordersOverlap.elm+46 deps/elm-ui/tests-rendering/cases/open/Scrollbar2.elm+39 deps/elm-ui/tests-rendering/cases/open/Scrollbars.elm+50 deps/elm-ui/tests-rendering/cases/open/StackedScrollingColumnsHeight.elm+42 deps/elm-ui/tests-rendering/cases/open/WeirdCentering.elm+35 deps/elm-ui/tests-rendering/cases/resolved/Adjusted.elm+70 deps/elm-ui/tests-rendering/cases/resolved/BehindContent.elm+34 deps/elm-ui/tests-rendering/cases/resolved/ClippedElInFixedWidthColumn.elm+31 deps/elm-ui/tests-rendering/cases/resolved/ColumnGrowth.elm+40 deps/elm-ui/tests-rendering/cases/resolved/ElInFixedHeightColumn.elm+41 deps/elm-ui/tests-rendering/cases/resolved/FocusStyles.elm+34 deps/elm-ui/tests-rendering/cases/resolved/HugePlaceholder.elm+25 deps/elm-ui/tests-rendering/cases/resolved/Images/ImageRegression.elm+63 deps/elm-ui/tests-rendering/cases/resolved/Images/ImageRegression2.elm+19 deps/elm-ui/tests-rendering/cases/resolved/Images/ImageSizing.elm+24 deps/elm-ui/tests-rendering/cases/resolved/Input/FocusLinks.elm+37 deps/elm-ui/tests-rendering/cases/resolved/Input/FocusStylePrecedingElements.elm+38 deps/elm-ui/tests-rendering/cases/resolved/Input/InputAlignment.elm+44 deps/elm-ui/tests-rendering/cases/resolved/Input/LabelAlignBaseline.elm+34 deps/elm-ui/tests-rendering/cases/resolved/Input/Placeholder.elm+59 deps/elm-ui/tests-rendering/cases/resolved/Input/Slider.elm+74 deps/elm-ui/tests-rendering/cases/resolved/Layout/BreaksWithinParagraph.elm+17 deps/elm-ui/tests-rendering/cases/resolved/Layout/ColumnLayouts.elm+103 deps/elm-ui/tests-rendering/cases/resolved/Layout/Columns/DistributeHeight.elm+46 deps/elm-ui/tests-rendering/cases/resolved/Layout/Columns/DistributeHeightCorrectly2.elm+86 deps/elm-ui/tests-rendering/cases/resolved/Layout/Columns/DoNotCollapseBelow0.elm+48 deps/elm-ui/tests-rendering/cases/resolved/Layout/Columns/SafariTwo.elm+40 deps/elm-ui/tests-rendering/cases/resolved/Layout/NestedParagraphs.elm+165 deps/elm-ui/tests-rendering/cases/resolved/Layout/Rounded.elm+54 deps/elm-ui/tests-rendering/cases/resolved/Layout/SafariBugIssue147.elm+37 deps/elm-ui/tests-rendering/cases/resolved/Layout/WrapRow.elm+13 deps/elm-ui/tests-rendering/cases/resolved/Misc/Scroll.elm+48 deps/elm-ui/tests-rendering/cases/resolved/MismatchTextInputText.elm+82 deps/elm-ui/tests-rendering/cases/resolved/MultilineCollapsed.elm+61 deps/elm-ui/tests-rendering/cases/resolved/MultilineInput.elm+377 deps/elm-ui/tests-rendering/cases/resolved/MultilineNewline.elm+61 deps/elm-ui/tests-rendering/cases/resolved/Nearby/InFrontIssue.elm+64 deps/elm-ui/tests-rendering/cases/resolved/Nearby/Issue22ZIndex.elm+87 deps/elm-ui/tests-rendering/cases/resolved/Nearby/OtherInFrontIssue.elm+55 deps/elm-ui/tests-rendering/cases/resolved/Nearby/ZIndexRegression.elm+43 deps/elm-ui/tests-rendering/cases/resolved/NestedColumns.elm+33 deps/elm-ui/tests-rendering/cases/resolved/OtherOtherZindex.elm+31 deps/elm-ui/tests-rendering/cases/resolved/OtherZIndex.elm+85 deps/elm-ui/tests-rendering/cases/resolved/OverflowingInput.elm+48 deps/elm-ui/tests-rendering/cases/resolved/OverflowingInput2.elm+54 deps/elm-ui/tests-rendering/cases/resolved/OverflowingInput3.elm+95 deps/elm-ui/tests-rendering/cases/resolved/ReversedTableOrder.elm+56 deps/elm-ui/tests-rendering/cases/resolved/TextAreaMax.elm+80 deps/elm-ui/tests-rendering/cases/resolved/WeirdWrapping.elm+32 deps/elm-ui/tests-rendering/cases/resolved/ZIndex.elm+56 deps/elm-ui/tests-rendering/cases/resolved/elm.json+25 deps/elm-ui/tests-rendering/elm.json+25 deps/elm-ui/tests-rendering/src/Generator.elm+53 deps/elm-ui/tests-rendering/src/Testable.elm+940 deps/elm-ui/tests-rendering/src/Testable/Element.elm+1723 deps/elm-ui/tests-rendering/src/Testable/Element/Background.elm+28 deps/elm-ui/tests-rendering/src/Testable/Element/Border.elm+20 deps/elm-ui/tests-rendering/src/Testable/Element/Font.elm+56 deps/elm-ui/tests-rendering/src/Testable/Generator.elm+398 deps/elm-ui/tests-rendering/src/Testable/Runner.elm+607 deps/elm-ui/tests-rendering/src/Tests/Alignment.elm+49 deps/elm-ui/tests-rendering/src/Tests/All.elm+44 deps/elm-ui/tests-rendering/src/Tests/Nearby.elm+179 deps/elm-ui/tests-rendering/src/Tests/Palette.elm+45 deps/elm-ui/tests-rendering/src/Tests/Run.elm+14 deps/elm-ui/tests-rendering/src/Tests/Spacing.elm+36 deps/elm-ui/tests-rendering/src/Tests/Table.elm.todo+123 deps/elm-ui/tests-rendering/src/Tests/TextWrapping.elm+51 deps/elm-ui/tests-rendering/src/Tests/Transparency.elm+57 deps/elm-ui/tests-rendering/src/Tests/WidthHeight.elm+61 deps/elm-ui/tests/ClassNames.elm+172 deps/elm-ui/tests/Flags.elm+78 deps/elm-ui/yarn.lock+1271 elm-pages.config.mjs+1 elm.json+2−2 public/NotoSans.ttf public/Unbounded.ttf style.css+24−3
app/Route/Index.elm+418−4
@@ -2,9 +2,14 @@ module Route.Index exposing (ActionData, Data, Model, Msg, route)
22
33import BackendTask exposing (BackendTask)
44import Element exposing (..)
5+import Element.Background as Background
6+import Element.Border as Border
7+import Element.Font as Font
58import FatalError exposing (FatalError)
69import Head
710import Head.Seo as Seo
11+import Html
12+import Html.Attributes as Html
813import Pages.Url
914import PagesMsg exposing (PagesMsg)
1015import Route
@@ -64,9 +69,9 @@ head app =
6469 , dimensions = Nothing
6570 , mimeType = Nothing
6671 }
67− , description = "Welcome to elm-pages!"
72+ , description = "Преимальный коворкинг у дома"
6873 , locale = Nothing
69− , title = "elm-pages is running"
74+ , title = "GigaWork"
7075 }
7176 |> Seo.website
7277
@@ -76,7 +81,416 @@ view :
7681 -> Shared.Model
7782 -> View (PagesMsg Msg)
7883view app shared =
79− { title = "elm-pages is running"
84+ { title = "GigaWork"
8085 , body =
81− text "Hello!"
86+ column [ width (fill |> maximum 700), centerX, padding 22, spacing 76 ]
87+ [ column []
88+ [ el [ unbounded, Font.color green, Font.heavy, Font.size 72 ]
89+ (text "GigaWork")
90+ , el
91+ [ paddingEach { top = 9, right = 0, left = 18, bottom = 0 }
92+ , noto
93+ , Font.size 18
94+ , Font.extraBold
95+ ]
96+ (text "Премиальный коворкинг у дома")
97+ ]
98+ , callToAction
99+ , column [ spacing 24, width fill ]
100+ [ subtitle "Преимущества"
101+ , wrappedRow [ spacing 16, centerX, width fill ]
102+ [ card
103+ { title = "Удобное расположение"
104+ , body = "10 минут от метро Молодежная.\nБесплатная парковка."
105+ , image = mockImage
106+ }
107+ , card
108+ { title = "Эргономичная мебель"
109+ , body = "Каждое рабочее место оснащено креслом Herman Miller."
110+ , image = mockImage
111+ }
112+ , card
113+ { title = "Свежий кофе"
114+ , body = "Каждую неделю заказываем для вас свежеобжаренный кофе."
115+ , image = mockImage
116+ }
117+ , card
118+ { title = "Проводной интернет"
119+ , body = "Каждое рабочее место оснащено выходом USB-C с зарядкой и интернетом."
120+ , image = mockImage
121+ }
122+ , card
123+ { title = "Принтер"
124+ , body = "Для вашего пользования есть лазерный принтер."
125+ , image = mockImage
126+ }
127+ , card
128+ { title = "Лаундж-зона"
129+ , body = "Предусмотрена лаундж-зона для отдыха."
130+ , image = mockImage
131+ }
132+ , card
133+ { title = "Кабинки для звонков"
134+ , body = "Чтобы не мешать друг другу в коворкинге стоят кабинки для звонков."
135+ , image = mockImage
136+ }
137+ , card
138+ { title = "Комфортные условия"
139+ , body = "В коворкинге установлен кондиционер и очиститель воздуха."
140+ , image = mockImage
141+ }
142+ ]
143+ ]
144+ , column [ spacing 27, width fill ]
145+ [ subtitle "График работы"
146+ , row [ width fill, spaceEvenly ]
147+ [ workDayCard { title = "Пн", from = "9:00", to = "18:00" }
148+ , workDayCard { title = "Вт", from = "9:00", to = "18:00" }
149+ , workDayCard { title = "Ср", from = "9:00", to = "18:00" }
150+ , workDayCard { title = "Чт", from = "9:00", to = "18:00" }
151+ , workDayCard { title = "Пт", from = "9:00", to = "18:00" }
152+ , weekendDayCard { title = "Сб" }
153+ , weekendDayCard { title = "Вс" }
154+ ]
155+ ]
156+ , column [ spacing 27, width fill ]
157+ [ subtitle "Адрес"
158+ , paragraph [ noto, Font.size 18, Font.extraBold ] [ text "Москва, Рублевское шоссе, 22" ]
159+ , el [ width fill, height (px 400) ] <|
160+ html <|
161+ Html.iframe
162+ [ Html.src "https://yandex.ru/map-widget/v1/?um=constructor%3A6021061543ae5cffca6803ac7a0fa84e727d918c403c59250d18022f582f81d0&amp;source=constructor"
163+ , Html.height 400
164+ , Html.attribute "frameborder" "0"
165+ ]
166+ []
167+ ]
168+ , column [ spacing 27, width fill ]
169+ [ subtitle "Цена"
170+ , row [ width fill, spaceEvenly ]
171+ [ priceCard { title = "1 день", price = "2 000 ₽", subtitle = "" }
172+ , priceCard { title = "1 месяц", price = "25 000 ₽", subtitle = "" }
173+ , priceCard { title = "3 месяца", price = "66 000 ₽", subtitle = "22 000 ₽ / месяц" }
174+ , priceCard { title = "6 месяца", price = "120 000 ₽", subtitle = "20 000 ₽ / месяц" }
175+ ]
176+ ]
177+ , callToAction
178+ ]
82179 }
180+
181+
182+mockImage : Element msg
183+mockImage =
184+ el
185+ [ Background.color (rgb 0.3 0.3 0.3)
186+ , width (px 1000)
187+ , height (px 1000)
188+ ]
189+ none
190+
191+
192+subtitle : String -> Element msg
193+subtitle t =
194+ paragraph [ Font.color green, Font.size 36, Font.heavy, unbounded ] [ text t ]
195+
196+
197+unbounded : Attribute msg
198+unbounded =
199+ Font.family [ Font.typeface "Unbounded" ]
200+
201+
202+noto : Attribute msg
203+noto =
204+ Font.family [ Font.typeface "Noto Sans" ]
205+
206+
207+green : Color
208+green =
209+ rgb255 32 195 145
210+
211+
212+background : Color
213+background =
214+ rgb255 243 243 243
215+
216+
217+button : String -> Element msg
218+button t =
219+ el
220+ [ Border.rounded 1000
221+ , Border.shadow
222+ { offset = ( 4, 4 )
223+ , size = 0
224+ , blur = 16
225+ , color = rgba255 0 0 0 0.2
226+ }
227+ , mouseOver
228+ [ Border.shadow
229+ { offset = ( 4, 4 )
230+ , size = 0
231+ , blur = 20
232+ , color = rgba255 0 0 0 0.2
233+ }
234+ ]
235+ , mouseDown
236+ [ Border.shadow
237+ { offset = ( 4, 4 )
238+ , size = 0
239+ , blur = 8
240+ , color = rgba255 0 0 0 0.2
241+ }
242+ ]
243+ , pointer
244+ , animate
245+ ]
246+ <|
247+ el
248+ [ Border.rounded 1000
249+ , Border.shadow
250+ { offset = ( -4, -4 )
251+ , size = 0
252+ , blur = 16
253+ , color = rgba 255 255 255 1
254+ }
255+ , mouseOver
256+ [ Border.shadow
257+ { offset = ( -4, -4 )
258+ , size = 0
259+ , blur = 20
260+ , color = rgba 255 255 255 1
261+ }
262+ ]
263+ , mouseDown
264+ [ Border.shadow
265+ { offset = ( -4, -4 )
266+ , size = 0
267+ , blur = 8
268+ , color = rgba 255 255 255 0.8
269+ }
270+ ]
271+ , animate
272+ ]
273+ <|
274+ el
275+ [ Background.color background
276+ , Border.rounded 1000
277+ , Border.innerShadow
278+ { offset = ( 4, 4 )
279+ , size = 0
280+ , blur = 4
281+ , color = rgba255 255 255 255 1
282+ }
283+ , mouseOver
284+ [ Border.innerShadow
285+ { offset = ( 4, 4 )
286+ , size = 0
287+ , blur = 8
288+ , color = rgba255 255 255 255 1
289+ }
290+ ]
291+ , mouseDown
292+ [ Border.innerShadow
293+ { offset = ( 4, 4 )
294+ , size = 0
295+ , blur = 2
296+ , color = rgba255 255 255 255 1
297+ }
298+ ]
299+ , animate
300+ ]
301+ <|
302+ el
303+ [ Border.innerShadow
304+ { offset = ( -4, -4 )
305+ , size = 0
306+ , blur = 4
307+ , color = rgba255 0 0 0 0.15
308+ }
309+ , mouseOver
310+ [ Border.innerShadow
311+ { offset = ( -4, -4 )
312+ , size = 0
313+ , blur = 8
314+ , color = rgba255 0 0 0 0.2
315+ }
316+ ]
317+ , mouseDown
318+ [ Border.innerShadow
319+ { offset = ( -4, -4 )
320+ , size = 0
321+ , blur = 2
322+ , color = rgba255 0 0 0 0.2
323+ }
324+ ]
325+ , padding 24
326+ , Border.rounded 1000
327+ , Font.extraBold
328+ , Font.size 18
329+ , animate
330+ ]
331+ (text t)
332+
333+
334+card : { title : String, body : String, image : Element msg } -> Element msg
335+card { title, body, image } =
336+ el
337+ [ Border.shadow
338+ { offset = ( -4, -4 )
339+ , blur = 16
340+ , size = 0
341+ , color = rgb 255 255 255
342+ }
343+ , Border.rounded 16
344+ , width (minimum 312 <| fill)
345+ , alignTop
346+ ]
347+ <|
348+ column
349+ [ Border.shadow
350+ { offset = ( 4, 4 )
351+ , blur = 16
352+ , size = 0
353+ , color = rgba 0 0 0 0.2
354+ }
355+ , Border.rounded 16
356+ , width fill
357+ ]
358+ [ column
359+ [ padding 16
360+ , spacing 8
361+ ]
362+ [ paragraph [ unbounded, Font.extraBold, Font.size 18, spacing 2 ] [ text title ]
363+ , paragraph [ noto, Font.size 14, spacing 1 ] [ text body ]
364+ ]
365+ , el
366+ [ height (px 156)
367+ , width fill
368+ , clip
369+ , centerX
370+ , centerY
371+ , Border.roundEach
372+ { topLeft = 0
373+ , topRight = 0
374+ , bottomLeft = 16
375+ , bottomRight = 16
376+ }
377+ ]
378+ image
379+ ]
380+
381+
382+animate : Attribute msg
383+animate =
384+ htmlAttribute <| Html.class "animate"
385+
386+
387+indentedCard : { title : String, body : Element msg, color : Color, minWidth : Int } -> Element msg
388+indentedCard { title, body, color, minWidth } =
389+ el
390+ [ Background.color color
391+ , Border.shadow
392+ { offset = ( 4, 4 )
393+ , blur = 16
394+ , size = 0
395+ , color = rgba255 0 0 0 0.2
396+ }
397+ , Border.rounded 16
398+ ]
399+ <|
400+ el
401+ [ Border.shadow
402+ { offset = ( -4, -4 )
403+ , blur = 16
404+ , size = 0
405+ , color = rgb255 255 255 255
406+ }
407+ , Border.rounded 16
408+ ]
409+ <|
410+ column [ padding 4, width (minimum minWidth <| fill), height (px 132) ]
411+ [ el
412+ [ height (px 38)
413+ , unbounded
414+ , width fill
415+ , Font.heavy
416+ , Font.size 14
417+ , Border.innerShadow
418+ { offset = ( 4, 4 )
419+ , blur = 4
420+ , size = 0
421+ , color = rgba255 0 0 0 0.15
422+ }
423+ , Border.roundEach
424+ { topLeft = 14
425+ , topRight = 14
426+ , bottomLeft = 0
427+ , bottomRight = 0
428+ }
429+ , Background.color background
430+ ]
431+ <|
432+ el
433+ [ width fill
434+ , height fill
435+ , Border.innerShadow
436+ { offset = ( -4, -4 )
437+ , blur = 4
438+ , size = 0
439+ , color = rgb255 255 255 255
440+ }
441+ , Border.roundEach
442+ { topLeft = 14
443+ , topRight = 14
444+ , bottomLeft = 0
445+ , bottomRight = 0
446+ }
447+ ]
448+ <|
449+ el [ centerX, centerY ]
450+ (text title)
451+ , body
452+ ]
453+
454+
455+workDayCard : { title : String, from : String, to : String } -> Element msg
456+workDayCard { title, from, to } =
457+ indentedCard
458+ { title = title
459+ , body =
460+ column [ centerX, centerY, unbounded, Font.size 14, Font.heavy, spacing 5 ] <|
461+ List.map (el [ centerX ])
462+ [ text from, text "—", text to ]
463+ , color = background
464+ , minWidth = 65
465+ }
466+
467+
468+weekendDayCard : { title : String } -> Element msg
469+weekendDayCard { title } =
470+ indentedCard
471+ { title = title
472+ , body =
473+ el [ centerX, centerY, unbounded, Font.size 14, Font.heavy, spacing 5 ] <|
474+ el [ centerX ] (text "Вых.")
475+ , color = rgb255 246 214 214
476+ , minWidth = 65
477+ }
478+
479+
480+priceCard : { title : String, price : String, subtitle : String } -> Element msg
481+priceCard cfg =
482+ indentedCard
483+ { title = cfg.title
484+ , color = background
485+ , body =
486+ column [ centerX, centerY, spacing 5 ] <|
487+ [ el [ centerX, unbounded, Font.size 14, Font.heavy ] (text cfg.price)
488+ , el [ centerX, noto, Font.size 14, Font.regular ] (text cfg.subtitle)
489+ ]
490+ , minWidth = 148
491+ }
492+
493+
494+callToAction : Element msg
495+callToAction =
496+ el [ centerX ] <| link [] { url = "https://t.me/ilyakooo0", label = button "Узнать о свободных местах" }
app/Shared.elm+2−1
@@ -3,6 +3,7 @@ module Shared exposing (Data, Model, Msg(..), SharedMsg(..), template)
33import BackendTask exposing (BackendTask)
44import Effect exposing (Effect)
55import Element exposing (..)
6+import Element.Background as Background
67import FatalError exposing (FatalError)
78import Html exposing (Html)
89import Pages.Flags
@@ -92,6 +93,6 @@ view :
9293 -> View msg
9394 -> { body : List (Html msg), title : String }
9495view sharedData page model toMsg pageView =
95− { body = [ layout [] pageView.body ]
96+ { body = [ layout [ Background.color (rgb255 243 243 243) ] pageView.body ]
9697 , title = pageView.title
9798 }
deps/elm-ui/.github/ISSUE_TEMPLATE/bug-unexpected-behavior-report.mdnew file+21
@@ -0,0 +1,21 @@
1+---
2+name: Bug/Unexpected behavior report
3+about: Capture any unexpected behavior or bugs you've found with this library
4+
5+---
6+
7+**Welcome!**
8+
9+If you can, please put together a [Short, Self Contained, Correct, Example](http://sscce.org/) of what you're encountering. It really helps if the example is as succinct as possible.
10+
11+Here's a basic template in [ellie](https://www.ellie-app.com/3fhCyrxjLw3a1) to get you started!
12+
13+**Expected behavior**
14+A clear and concise description of what you expected to happen.
15+
16+**Versions**
17+ - OS: [e.g. iOS]
18+ - Browser [e.g. chrome, safari]
19+ - Browser Version
20+ - Elm Version
21+ - Elm UI Version [e.g. ]
deps/elm-ui/.github/workflows/docs-preview.ymlnew file+36
@@ -0,0 +1,36 @@
1+# This is a basic workflow to help you get started with Actions
2+
3+name: Documentation
4+
5+# Controls when the action will run. Triggers the workflow on push or pull request
6+# events but only for the master branch
7+on:
8+ push:
9+ branches: [ master ]
10+ pull_request:
11+ branches: [ master ]
12+
13+# A workflow run is made up of one or more jobs that can run sequentially or in parallel
14+jobs:
15+ # This workflow contains a single job called "build"
16+ build:
17+ # The type of runner that the job will run on
18+ runs-on: ubuntu-latest
19+
20+
21+ # Steps represent a sequence of tasks that will be executed as part of the job
22+ steps:
23+ # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
24+ - uses: actions/checkout@v2
25+
26+ - name: Setup node
27+ uses: actions/setup-node@v1
28+ with:
29+ node-version: 10
30+
31+ - name: Install
32+ run: npm install
33+
34+ # Runs a single command using the runners shell
35+ - name: Run a one-line script
36+ run: npm run test-doc-preview
deps/elm-ui/.github/workflows/label-issues-from-body.ymlnew file+14
@@ -0,0 +1,14 @@
1+name: "Label issue from body keyword"
2+on:
3+ issues:
4+ types: [opened, edited]
5+
6+jobs:
7+ test:
8+ runs-on: ubuntu-latest
9+ steps:
10+ - uses: Naturalclar/issue-action@v1.0.0
11+ with:
12+ keywords: '["https://ellie-app.com/"]'
13+ labels: '["has-ellie"]'
14+ github-token: "${{ secrets.GITHUB_TOKEN }}"
deps/elm-ui/.github/workflows/label-issues-from-comments.ymlnew file+59
@@ -0,0 +1,59 @@
1+name: "Label issue from comment keyword"
2+on:
3+ issue_comment:
4+ types: [created, edited]
5+
6+jobs:
7+ test:
8+ runs-on: ubuntu-latest
9+ steps:
10+ - uses: Amwam/issue-comment-action@v1.3.1
11+ with:
12+ keywords: '["#bug"]'
13+ labels: '["bug"]'
14+ github-token: "${{ secrets.GITHUB_TOKEN }}"
15+ - uses: Amwam/issue-comment-action@v1.3.1
16+ with:
17+ keywords: '["#feature-suggestion"]'
18+ labels: '["feature-suggestion"]'
19+ github-token: "${{ secrets.GITHUB_TOKEN }}"
20+ - uses: Amwam/issue-comment-action@v1.3.1
21+ with:
22+ keywords: '["#has-ellie", "https://ellie-app.com/"]'
23+ labels: '["has-ellie"]'
24+ github-token: "${{ secrets.GITHUB_TOKEN }}"
25+ - uses: Amwam/issue-comment-action@v1.3.1
26+ with:
27+ keywords: '["#no-ellie"]'
28+ labels: '["no-ellie"]'
29+ github-token: "${{ secrets.GITHUB_TOKEN }}"
30+ - uses: Amwam/issue-comment-action@v1.3.1
31+ with:
32+ keywords: '["#has-test"]'
33+ labels: '["has-test"]'
34+ github-token: "${{ secrets.GITHUB_TOKEN }}"
35+ - uses: Amwam/issue-comment-action@v1.3.1
36+ with:
37+ keywords: '["#pain-point"]'
38+ labels: '["pain-point"]'
39+ github-token: "${{ secrets.GITHUB_TOKEN }}"
40+ - uses: Amwam/issue-comment-action@v1.3.1
41+ with:
42+ keywords: '["#test-incorrectly-passing"]'
43+ labels: '["test-incorrectly-passing"]'
44+ github-token: "${{ secrets.GITHUB_TOKEN }}"
45+ - uses: Amwam/issue-comment-action@v1.3.1
46+ with:
47+ keywords: '["#test-not-compiling"]'
48+ labels: '["test-not-compiling"]'
49+ github-token: "${{ secrets.GITHUB_TOKEN }}"
50+ - uses: Amwam/issue-comment-action@v1.3.1
51+ with:
52+ keywords: '["#test-failing"]'
53+ labels: '["test-failing"]'
54+ github-token: "${{ secrets.GITHUB_TOKEN }}"
55+ - uses: Amwam/issue-comment-action@v1.3.1
56+ with:
57+ keywords: '["#unexpected"]'
58+ labels: '["unexpected"]'
59+ github-token: "${{ secrets.GITHUB_TOKEN }}"
deps/elm-ui/.github/workflows/tests.ymlnew file+43
@@ -0,0 +1,43 @@
1+name: Test Suite
2+
3+on:
4+ push:
5+ branches: [ master ]
6+ pull_request:
7+ branches: [ master ]
8+
9+
10+jobs:
11+ testing:
12+ runs-on: ubuntu-latest
13+
14+ steps:
15+ - uses: actions/checkout@v2
16+
17+ - name: Setup node
18+ uses: actions/setup-node@v1
19+ with:
20+ node-version: 10
21+
22+ - uses: actions/cache@v1
23+ with:
24+ path: ~/.npm
25+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
26+ restore-keys: |
27+ ${{ runner.os }}-node-
28+
29+ - name: Install
30+ run: npm ci
31+
32+ - name: Elm test suite
33+ run: npm run test
34+
35+ - uses: webfactory/ssh-agent@v0.2.0
36+ with:
37+ ssh-private-key: ${{ secrets.ELM_UI_TESTING_SSH_PRIVATE_KEY }}
38+
39+ - name: Rendering test suite on saucelabs
40+ run: npm run test-render-sauce-automated -- --build=2.0.0 --name=development
41+ env:
42+ SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
43+ SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
deps/elm-ui/.gitignorenew file+28
@@ -0,0 +1,28 @@
1+# elm-package generated files
2+elm-stuff/
3+# elm-repl generated files
4+repl-temp-*
5+.DS_Store
6+*/index.html
7+index.html
8+.elm-static-html
9+
10+tests/html-generation/rendered/
11+
12+env
13+elm.js
14+
15+examples/temporary/
16+
17+.vscode
18+
19+
20+sauce.env
21+
22+__pycache__
23+node_modules
24+benchmarks/tmp
25+benchmarks/results
26+tests/tmp
27+
28+tmp
deps/elm-ui/CONTRIBUTING.mdnew file+25
@@ -0,0 +1,25 @@
1+# Contributing to Elm UI
2+
3+Welcome!
4+
5+First, if you have a question about how to do something with the library, join `#elm-ui` on the [Elm Slack](https://elmlang.herokuapp.com/)! There are usually a number of people who are willing to help out, myself included.
6+
7+That's the place to ask questions, try there first.
8+
9+A few notes about my design process for `elm-ui`.
10+
11+I don't usually accept PRs that add features. Mainly this is because there is a bunch of design thought and research that needs to be done before a feature can be added.
12+
13+So, here are some other ways you can help if you so desire!
14+
15+# Bugs and Unexpected Things
16+
17+If you run into unexpected behavior, I definitely want to hear about it. Put together a [Short, Self Contained, Correct, Example](http://sscce.org/) of what you're encountering. It really helps if the example is as succinct as possible.
18+
19+Here's a basic template in [ellie](https://ellie-app.com/3fhCyrxjLw3a1) to get you started!
20+
21+# Research
22+
23+One of the more challenging parts of the project like this is gathering information.
24+
25+If you know of good resources about accessibility, internationalization, design, or [any of the topics listed in the research folder](https://github.com/mdgriffith/elm-ui/tree/master/notes/research), send them my way either via PR to those documents or on slack.
deps/elm-ui/CSS-LOOKUP.mdnew file+18
@@ -0,0 +1,18 @@
1+# CSS Concepts and where to find them
2+
3+This library creates a new language around layout and style, though if you're already used to CSS, you're probably wondering where certain concepts lie.
4+
5+> I know how I can do it in CSS, but how could I approach the problem using Style Elements?
6+
7+
8+CSS | Style Elements | Description
9+-------|------------------|------------
10+`position:absolute` | `above`, `below`, `onRight`, `onLeft`, `inFront`, `behindContent` | In Style Elements we can attach elements relative to another element. They won't affect normal flow, just like `position:absolute`
11+`position:fixed` | `inFront` if it's attached to the `Element.layout` element. | `position:fixed` needs to be at the top of your view or else it can break in seemingly random ways. Did you know `position:fixed` will position something relative to the viewport *OR* any parent that uses `filter`, `transform` or `perspective`? So you add a blur effect and your layout breaks...
12+`z-index` | __N/A__ | One of the goals of the library was to make `z-index` a behind-the-scenes detail. If you ever encounter a situation where you feel like you actually need it, let me know on slack or through the issues.
13+`float:left` `float:right` | `alignLeft` or `alignRight` when inside a `paragraph` or a `textColumn` |
14+`opacity` | `alpha` |
15+`margin` | __N/A__ Instead, check out `padding` and `spacing` | `margin` in CSS was designed to fight with `padding`. This library was designed to minimize override logic and properties that fight with each other in order to create a layout language that is predictable and easy to think about. The result is that in style elements, there's generally only *one place* where an effect can happen.
16+`:hover`, `:focus`, `:active` | `mouseOver`, `focused`, `mouseDown` | Only certain styles are allowed to be in a pseudo state. They have the type `Attr decorative msg`, which means they can be either an `Attribute` or a `Decoration`.
17+`<form>` | __N/a__ | __Elm__ already has a mechanism for submiting data to a server, namely the `Http` package. There has been some mention that the `form` element might be beneficial accessibility-wise, which I'm definitely open to hearing about!
18+`onSubmit` | __N/A__ | Similar to `<form>`, there is no `onSubmit` behavior. Likely if you're attempting to capture some of the keybaord related behavior of `onSubmit`, you're likely better just crafting a keyboard event handler in the first place!
deps/elm-ui/LICENSEnew file+27
@@ -0,0 +1,27 @@
1+Copyright (c) 2020, Matthew Griffith
2+All rights reserved.
3+
4+Redistribution and use in source and binary forms, with or without
5+modification, are permitted provided that the following conditions are met:
6+
7+* Redistributions of source code must retain the above copyright notice, this
8+ list of conditions and the following disclaimer.
9+
10+* Redistributions in binary form must reproduce the above copyright notice,
11+ this list of conditions and the following disclaimer in the documentation
12+ and/or other materials provided with the distribution.
13+
14+* Neither the name of Elm UI nor the names of its
15+ contributors may be used to endorse or promote products derived from
16+ this software without specific prior written permission.
17+
18+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
deps/elm-ui/README.mdnew file+77
@@ -0,0 +1,77 @@
1+![](https://github.com/mdgriffith/elm-ui/workflows/Test%20Suite/badge.svg)
2+
3+
4+Check out the talk that goes with the library, [Building a Better Design Toolkit](https://www.youtube.com/watch?v=Ie-gqwSHQr0&t=2s)
5+
6+# A New Language for Layout and Interface
7+
8+CSS and HTML are actually quite difficult to use when you're trying to do the layout and styling of a web page.
9+
10+This library is a complete alternative to HTML and CSS. Basically you can just write your app using this library and (mostly) never have to think about HTML and CSS again.
11+
12+The high level goal of this library is to be a **design toolkit** that draws inspiration from the domains of design, layout, and typography, as opposed to drawing from the ideas as implemented in CSS and HTML.
13+
14+This means:
15+
16+* Writing and designing your layout and `view` should be as **simple and as fun** as possible.
17+* Many layout errors (like you'd run into using CSS) **are just not possible to write** in the first place!
18+* Everything should just **run fast.**
19+* **Layout and style are explicit and easy to modify.** CSS and HTML as tools for a layout language are hard to modify because there's no central place that represents your layout. You're generally forced to bounce back and forth between multiple definitions in multiple files in order to adjust layout, even though it's probably the most common thing you'll do.
20+
21+
22+[Try this live example on Ellie!](https://ellie-app.com/7Cw4VCyr3RGa1)
23+
24+```elm
25+module Main exposing (..)
26+
27+import Element exposing (Element, el, text, row, alignRight, fill, width, rgb255, spacing, centerY, padding)
28+import Element.Background as Background
29+import Element.Border as Border
30+import Element.Font as Font
31+
32+
33+main =
34+ Element.layout []
35+ myRowOfStuff
36+
37+myRowOfStuff : Element msg
38+myRowOfStuff =
39+ row [ width fill, centerY, spacing 30 ]
40+ [ myElement
41+ , myElement
42+ , el [ alignRight ] myElement
43+ ]
44+
45+
46+myElement : Element msg
47+myElement =
48+ el
49+ [ Background.color (rgb255 240 0 245)
50+ , Font.color (rgb255 255 255 255)
51+ , Border.rounded 3
52+ , padding 30
53+ ]
54+ (text "stylish!")
55+```
56+
57+# Join the Elm UI Slack!
58+
59+First, if you have a question about how to do something with the library, join `#elm-ui` on the [Elm Slack](https://elmlang.herokuapp.com/)! There are usually a number of people who are willing to help out, myself included.
60+
61+## History
62+
63+The work is based off of a rewrite of the [Style Elements](https://github.com/mdgriffith/style-elements) library. A lot of that work was originally released under the [Stylish Elephants](https://github.com/mdgriffith/stylish-elephants) project.
64+
65+## Community Cookbook
66+
67+The 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+
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+
73+## Contributing
74+
75+Want to help out fixing bugs or reporting issues?
76+
77+Please add issues you find, and if you want to verify code you want to contribute, please read how to run the tests [here](https://github.com/mdgriffith/elm-ui/blob/master/notes/RUNNING_TESTS.md).
deps/elm-ui/benchmarks/elm.jsonnew file+34
@@ -0,0 +1,34 @@
1+{
2+ "type": "application",
3+ "source-directories": [
4+ "src",
5+ "../src"
6+ ],
7+ "elm-version": "0.19.1",
8+ "dependencies": {
9+ "direct": {
10+ "avh4/elm-color": "1.0.0",
11+ "elm/browser": "1.0.1",
12+ "elm/core": "1.0.2",
13+ "elm/html": "1.0.0",
14+ "elm/json": "1.1.3",
15+ "elm/time": "1.0.0",
16+ "elm/virtual-dom": "1.0.2",
17+ "terezka/line-charts": "2.0.0"
18+ },
19+ "indirect": {
20+ "debois/elm-dom": "1.3.0",
21+ "elm/parser": "1.1.0",
22+ "elm/svg": "1.0.1",
23+ "elm/url": "1.0.0",
24+ "justinmimbs/date": "3.1.2",
25+ "justinmimbs/time-extra": "1.1.0",
26+ "myrho/elm-round": "1.0.4",
27+ "ryannhg/date-format": "2.3.0"
28+ }
29+ },
30+ "test-dependencies": {
31+ "direct": {},
32+ "indirect": {}
33+ }
34+}
deps/elm-ui/benchmarks/micro/Suite.elmnew file+330
@@ -0,0 +1,330 @@
1+module Suite exposing (main)
2+
3+import Benchmark exposing (Benchmark)
4+import Benchmark.Runner exposing (BenchmarkProgram, program)
5+import Dict
6+import Element exposing (..)
7+import Element.Background as Background
8+import Element.Font as Font
9+import Html
10+import Html.Attributes
11+import Internal.Flag as Flag
12+import Internal.Model as Internal
13+import Json.Encode
14+import Set
15+
16+
17+dict : Benchmark
18+dict =
19+ let
20+ dest =
21+ Dict.singleton "a" 1
22+ in
23+ Benchmark.describe "dictionary"
24+ [ Benchmark.benchmark "get" (\_ -> Dict.get "a" dest)
25+ , Benchmark.benchmark "insert" (\_ -> Dict.insert "b" 2 dest)
26+ ]
27+
28+
29+main : BenchmarkProgram
30+main =
31+ program <|
32+ Benchmark.describe "sample"
33+ [ --dict
34+ -- , deduplications
35+ -- renderPipeline
36+ gatheringAttributes
37+
38+ -- flagOperations
39+ ]
40+
41+
42+flagOperations =
43+ Benchmark.describe "Flag Operations"
44+ [ Benchmark.benchmark "check if present" <|
45+ \_ ->
46+ Flag.present Flag.height Flag.none
47+ , Benchmark.benchmark "add to flagt" <|
48+ \_ ->
49+ Flag.add Flag.height Flag.none
50+ ]
51+
52+
53+gatheringAttributes =
54+ Benchmark.describe "Gathering Attributes"
55+ [ Benchmark.benchmark "existing - gatherAttrRecursive" <|
56+ \_ ->
57+ Internal.gatherAttrRecursive
58+ (Internal.contextClasses Internal.AsEl)
59+ Internal.Generic
60+ Flag.none
61+ Internal.Untransformed
62+ []
63+ []
64+ Internal.NoNearbyChildren
65+ [ Element.width Element.shrink
66+ , Element.height Element.shrink
67+ ]
68+ , Benchmark.benchmark "Simple list filterMap" <|
69+ \_ ->
70+ List.filterMap
71+ identity
72+ [ Just "thing"
73+ , Just "other width"
74+ ]
75+ , Benchmark.benchmark "Simple list map" <|
76+ \_ ->
77+ List.map
78+ identity
79+ [ Just "thing"
80+ , Just "other width"
81+ ]
82+ , Benchmark.benchmark "Foldl base speed" <|
83+ \_ ->
84+ List.foldl
85+ (::)
86+ [ Just "thing"
87+ , Just "other width"
88+ ]
89+ , Benchmark.benchmark "Recursive" <|
90+ \_ ->
91+ recurse
92+ (::)
93+ [ Just "thing"
94+ , Just "other width"
95+ ]
96+ , Benchmark.benchmark "foldl - new record each iteration" <|
97+ \_ ->
98+ List.foldl flipFoldl
99+ { attributes = "class"
100+ , styles = []
101+ , node = "Node"
102+ , children = Nothing
103+ , has = Flag.none
104+ }
105+ -- we reverse first because we have to for the attr api.
106+ (List.reverse
107+ [ Just "thing"
108+ , Just "other width"
109+ ]
110+ )
111+ , Benchmark.benchmark "foldl - update" <|
112+ \_ ->
113+ List.foldl flipFoldlUpdate
114+ { attributes = "class"
115+ , styles = []
116+ , node = "Node"
117+ , children = Nothing
118+ , has = Flag.none
119+ }
120+ -- we reverse first because we have to for the attr api.
121+ (List.reverse
122+ [ Just "thing"
123+ , Just "other width"
124+ ]
125+ )
126+ , Benchmark.benchmark "String Concatenation" <|
127+ \_ ->
128+ "This"
129+ ++ "this"
130+ ++ "this"
131+ ++ "this"
132+ ++ "this"
133+ ++ "this"
134+ ++ "this"
135+ ++ "this"
136+ , Benchmark.benchmark "List String Concatenation" <|
137+ \_ ->
138+ String.concat
139+ [ "This"
140+ , "this"
141+ , "this"
142+ , "this"
143+ , "this"
144+ , "this"
145+ , "this"
146+ , "this"
147+ ]
148+ ]
149+
150+
151+flipFoldl result found =
152+ { attributes = "class" ++ found.attributes
153+ , styles = Just 1 :: found.styles
154+ , node = found.node
155+ , children = Nothing
156+ , has = Flag.add Flag.height found.has
157+ }
158+
159+
160+flipFoldlUpdate result found =
161+ { found
162+ | attributes = "class" ++ found.attributes
163+ , styles = Just 1 :: found.styles
164+ , has = Flag.add Flag.height found.has
165+ }
166+
167+
168+recurse fn ls =
169+ case ls of
170+ [] ->
171+ []
172+
173+ fst :: remain ->
174+ fn fst (recurse fn remain)
175+
176+
177+deduplications =
178+ Benchmark.describe "deduplications"
179+ [ Benchmark.benchmark "fold - dedup, String concat"
180+ (\_ ->
181+ String.join ":" (foldDedup largeList)
182+ )
183+ , Benchmark.benchmark "fold - dedup"
184+ (\_ ->
185+ foldDedup largeList
186+ )
187+ , Benchmark.benchmark "fold - dedup - Int"
188+ (\_ ->
189+ foldDedup largeListInt
190+ )
191+ , Benchmark.benchmark "Json encode"
192+ (\_ ->
193+ Json.Encode.object largeListJson
194+ )
195+ ]
196+
197+
198+foldDedup list =
199+ let
200+ dedup ( name, val ) ( cache, ls ) =
201+ if Set.member name cache then
202+ ( cache, ls )
203+
204+ else
205+ ( Set.insert name cache, val :: ls )
206+ in
207+ List.foldl dedup ( Set.empty, [] ) list
208+ |> Tuple.second
209+
210+
211+largeListInt =
212+ List.range 1 10000
213+ |> List.map
214+ (\i ->
215+ let
216+ wrappingI =
217+ modBy 50 i
218+ in
219+ ( wrappingI, "elem-" ++ String.fromInt wrappingI )
220+ )
221+
222+
223+largeList =
224+ List.range 1 10000
225+ |> List.map
226+ (\i ->
227+ let
228+ wrappingI =
229+ modBy 50 i
230+ in
231+ ( "elem-" ++ String.fromInt wrappingI, "elem-" ++ String.fromInt wrappingI )
232+ )
233+
234+
235+largeListJson =
236+ List.range 1 10000
237+ |> List.map
238+ (\i ->
239+ let
240+ wrappingI =
241+ modBy 50 i
242+ in
243+ ( "elem-" ++ String.fromInt wrappingI, Json.Encode.string ("elem-" ++ String.fromInt wrappingI) )
244+ )
245+
246+
247+renderPipeline =
248+ [ Benchmark.benchmark "build 2000 elements"
249+ (\_ ->
250+ elements 0 twoThousand
251+ )
252+ , Benchmark.benchmark "build 2000 html"
253+ (\_ ->
254+ html 0 twoThousand
255+ )
256+ ]
257+
258+
259+twoThousand =
260+ List.range 0 2000
261+
262+
263+elements i count =
264+ Element.layout []
265+ (Element.column [ spacing 8, centerX ]
266+ (List.map (viewEl i) count)
267+ )
268+
269+
270+viewEl selectedIndex index =
271+ el
272+ [ Background.color
273+ (if selectedIndex == index then
274+ pink
275+
276+ else
277+ white
278+ )
279+ , Font.color
280+ (if selectedIndex /= index then
281+ pink
282+
283+ else
284+ white
285+ )
286+ , padding 24
287+ , width (px 500)
288+ , height (px 70)
289+ ]
290+ (if selectedIndex == index then
291+ text "selected"
292+
293+ else
294+ text "Hello!"
295+ )
296+
297+
298+white =
299+ rgb 1 1 1
300+
301+
302+pink =
303+ rgb255 240 0 245
304+
305+
306+html i count =
307+ Html.div []
308+ [ Html.div []
309+ (List.map (viewHtmlElement i) count)
310+ ]
311+
312+
313+viewHtmlElement selectedIndex index =
314+ Html.div
315+ [ Html.Attributes.class
316+ (if selectedIndex == index then
317+ "white"
318+
319+ else
320+ "pink"
321+ )
322+ ]
323+ [ Html.div []
324+ [ if selectedIndex == index then
325+ Html.text "selected"
326+
327+ else
328+ Html.text "Hello!"
329+ ]
330+ ]
deps/elm-ui/benchmarks/micro/elm.jsonnew file+30
@@ -0,0 +1,30 @@
1+{
2+ "type": "application",
3+ "source-directories": [
4+ ".",
5+ "../../src"
6+ ],
7+ "elm-version": "0.19.0",
8+ "dependencies": {
9+ "direct": {
10+ "elm/browser": "1.0.1",
11+ "elm/core": "1.0.2",
12+ "elm/html": "1.0.0",
13+ "elm/json": "1.1.3",
14+ "elm/time": "1.0.0",
15+ "elm/virtual-dom": "1.0.2",
16+ "elm-explorations/benchmark": "1.0.1"
17+ },
18+ "indirect": {
19+ "BrianHicks/elm-trend": "2.1.2",
20+ "Skinney/murmur3": "2.0.8",
21+ "elm/regex": "1.0.0",
22+ "elm/url": "1.0.0",
23+ "mdgriffith/style-elements": "5.0.1"
24+ }
25+ },
26+ "test-dependencies": {
27+ "direct": {},
28+ "indirect": {}
29+ }
30+}
deps/elm-ui/benchmarks/runtime/benchPage.jsnew file+146
@@ -0,0 +1,146 @@
1+const path = require('path');
2+
3+async function benchPage(page, file) {
4+ const client = await page.target().createCDPSession();
5+ await client.send('Performance.enable');
6+ // await page.tracing.start({ path: 'trace.json' });
7+ await page.goto('file://' + path.resolve(file))
8+
9+ await page.waitFor(5000);
10+ // await page.tracing.stop();
11+ const metrics = await client.send('Performance.getMetrics');
12+
13+ const startMetrics = await page.metrics()
14+ await page.evaluate(() => { window.elmRefresh() })
15+ await page.waitFor(1500);
16+ const endMetrics = await page.metrics()
17+
18+ await page.evaluate(() => { window.elmStartAnim() })
19+ await sleep(5000)
20+ await page.evaluate(() => { window.elmStopAnim() })
21+ await page.waitFor(2000);
22+ const finalMetrics = await page.metrics()
23+ const frames = await page.evaluate(x => {
24+ return Promise.resolve(window.metrics);
25+ }, {});
26+ return {
27+ name: frames.name,
28+ link: 'file://' + path.resolve(file),
29+ perf: extract(metrics),
30+ afterRefresh: {
31+ RecalcStyleDuration: endMetrics.RecalcStyleDuration - startMetrics.RecalcStyleDuration,
32+ LayoutDuration: endMetrics.LayoutDuration - startMetrics.LayoutDuration,
33+ ScriptDuration: endMetrics.ScriptDuration - startMetrics.ScriptDuration,
34+ JSHeapUsedSize: endMetrics.JSHeapUsedSize - startMetrics.JSHeapUsedSize
35+ },
36+ afterAnimation: {
37+ RecalcStyleDuration: finalMetrics.RecalcStyleDuration - endMetrics.RecalcStyleDuration,
38+ LayoutDuration: finalMetrics.LayoutDuration - endMetrics.LayoutDuration,
39+ ScriptDuration: finalMetrics.ScriptDuration - endMetrics.ScriptDuration,
40+ JSHeapUsedSize: finalMetrics.JSHeapUsedSize - endMetrics.JSHeapUsedSize
41+ },
42+ frames: summarize(frames.frames),
43+ }
44+}
45+
46+function summarize(frames) {
47+ return {
48+ count: frames.length,
49+ median: median(frames),
50+ mode: mode(frames),
51+ avg: average(frames),
52+ fps: 1000 / median(frames),
53+ min: minimum(frames),
54+ max: maximum(frames)
55+ }
56+}
57+
58+const keep = ["Timestamp", "Nodes", "LayoutDuration", "RecalcStyleDuration", "ScriptDuration", "JSHeapUsedSize", "FirstMeaningfulPaint", "DomContentLoaded", "NavigationStart"]
59+
60+
61+function extract(metrics) {
62+ var ext = {}
63+ metrics.metrics.forEach((item) => {
64+ if (keep.indexOf(item.name) >= 0) {
65+ ext[item.name] = item.value
66+ }
67+ })
68+ ext.TimeToFirstPaintMS = 1000 * (ext.FirstMeaningfulPaint - ext.DomContentLoaded)
69+ return ext
70+}
71+
72+function mode(array) {
73+ if (array.length == 0)
74+ return null;
75+ var modeMap = {};
76+ var maxEl = array[0], maxCount = 1;
77+ for (var i = 0; i < array.length; i++) {
78+ var el = array[i];
79+ if (modeMap[el] == null)
80+ modeMap[el] = 1;
81+ else
82+ modeMap[el]++;
83+ if (modeMap[el] > maxCount) {
84+ maxEl = el;
85+ maxCount = modeMap[el];
86+ }
87+ }
88+ return maxEl;
89+}
90+
91+function minimum(values) {
92+ var m = null
93+ for (var i = 0; i < values.length; i++) {
94+ if (m == null) {
95+ m = values[i]
96+ } else if (values[i] < m) {
97+ m = values[i]
98+ }
99+ }
100+ return m
101+}
102+
103+
104+function maximum(values) {
105+ var m = null
106+ for (var i = 0; i < values.length; i++) {
107+ if (m == null) {
108+ m = values[i]
109+ } else if (values[i] > m) {
110+ m = values[i]
111+ }
112+ }
113+ return m
114+}
115+
116+
117+function average(values) {
118+ var total = 0;
119+ for (var i = 0; i < values.length; i++) {
120+ total += values[i];
121+ }
122+ return total / values.length;
123+}
124+
125+function median(values) {
126+ if (values.length === 0) return 0;
127+
128+ values.sort(function (a, b) {
129+ return a - b;
130+ });
131+
132+ var half = Math.floor(values.length / 2);
133+
134+ if (values.length % 2)
135+ return values[half];
136+
137+ return (values[half - 1] + values[half]) / 2.0;
138+}
139+
140+
141+function sleep(ms) {
142+ return new Promise(resolve => {
143+ setTimeout(resolve, ms)
144+ })
145+}
146+module.exports = benchPage;
deps/elm-ui/benchmarks/runtime/index.jsnew file+176
@@ -0,0 +1,176 @@
1+const puppeteer = require('puppeteer');
2+const benchPage = require('./benchPage');
3+const chalk = require('chalk');
4+var compileToString = require("node-elm-compiler").compileToString;
5+const fs = require('fs');
6+
7+
8+
9+
10+
11+function write_entrypoint(item) {
12+
13+ const entrypoint = `module Main exposing (main)
14+import ${item.module}
15+import Benchmark.Render
16+
17+main = Benchmark.Render.toProgram ${item.module}.${item.value}
18+`
19+ fs.writeFileSync('./benchmarks/tmp/Main.elm', entrypoint);
20+}
21+
22+async function compile_and_embed(config) {
23+ var template = fs.readFileSync(config.template)
24+ // we embed the compiled js to avoid having to start a server to read the app.
25+ await compileToString(config.elm, config.elmOptions).then(function (compiled_elm_code) {
26+ const compiled = eval(`\`${template}\``)
27+ fs.writeFileSync(config.target, compiled)
28+ });
29+}
30+
31+
32+function regroupResults(results) {
33+ var regrouped = {}
34+
35+ for (var i = 0; i < results.length; i++) {
36+ if (results[i].group) {
37+
38+ var reorged = {
39+ name: results[i].name
40+ , link: results[i].link
41+ , count: results[i].count
42+ , fps: results[i].frames.fps
43+ , timeToFirstPaintMS: results[i].perf.TimeToFirstPaintMS
44+ , nodes: results[i].perf.Nodes
45+ , coldRender: {
46+ layoutSeconds: results[i].perf.LayoutDuration
47+ , recalcStyleSeconds: results[i].perf.RecalcStyleDuration
48+ , scriptDurationSeconds: results[i].perf.ScriptDuration
49+
50+ }
51+ , warmRender: {
52+ layoutSeconds: results[i].afterRefresh.LayoutDuration
53+ , recalcStyleSeconds: results[i].afterRefresh.RecalcStyleDuration
54+ , scriptDurationSeconds: results[i].afterRefresh.ScriptDuration
55+
56+ }
57+ , extendedRender: {
58+ layoutSeconds: results[i].afterAnimation.LayoutDuration
59+ , recalcStyleSeconds: results[i].afterAnimation.RecalcStyleDuration
60+ , scriptDurationSeconds: results[i].afterAnimation.ScriptDuration
61+
62+ }
63+
64+ }
65+ if (results[i].group in regrouped) {
66+ regrouped[results[i].group].results.push(reorged)
67+ } else {
68+ regrouped[results[i].group] = { results: [reorged], name: results[i].group }
69+ }
70+ }
71+ }
72+ return Object.values(regrouped)
73+}
74+
75+
76+var contain = [{ module: "Contain", group: "html", count: 1024, value: "viewHtml8192" }
77+ , { module: "Contain", group: "contain", count: 128, value: "viewHtmlContain8192" }]
78+
79+
80+async function writeResults(allResults, resultsDir, name) {
81+
82+ if (!fs.existsSync(resultsDir)) {
83+ fs.mkdirSync(resultsDir);
84+ }
85+ var results = JSON.stringify(allResults)
86+ var template = fs.readFileSync("./benchmarks/runtime/template/viewResults.html")
87+ // we embed the compiled js to avoid having to start a server to read the app.
88+ await compileToString(["./src/View/Results.elm"], { optimize: true, cwd: "./benchmarks" }).then(function (compiled_elm_code) {
89+ const compiled = eval(`\`${template}\``)
90+ fs.writeFileSync(`./${resultsDir}/${name}/index.html`, compiled)
91+ });
92+
93+ // fs.writeFileSync(`./${resultsDir}/1.1.1-candidate-optimized.json`, results)
94+}
95+
96+
97+(async () => {
98+ const browser = await puppeteer.launch();
99+
100+
101+ var instances = [
102+ { module: "ManyElements", group: "elmUI", count: 1024, value: "elmUI1024" }
103+ , { module: "ManyElements", group: "elmUI", count: 128, value: "elmUI128" }
104+ , { module: "ManyElements", group: "elmUI", count: 2048, value: "elmUI2048" }
105+ , { module: "ManyElements", group: "elmUI", count: 24, value: "elmUI24" }
106+ , { module: "ManyElements", group: "elmUI", count: 4096, value: "elmUI4096" }
107+ , { module: "ManyElements", group: "elmUI", count: 8192, value: "elmUI8192" }
108+ , { module: "ManyElements", group: "elmUIVCSS", count: 1024, value: "elmUIVCSS1024" }
109+ , { module: "ManyElements", group: "elmUIVCSS", count: 2048, value: "elmUIVCSS2048" }
110+ , { module: "ManyElements", group: "elmUIVCSS", count: 24, value: "elmUIVCSS24" }
111+ , { module: "ManyElements", group: "elmUIVCSS", count: 4096, value: "elmUIVCSS4096" }
112+ , { module: "ManyElements", group: "elmUIVCSS", count: 8192, value: "elmUIVCSS8192" }
113+ , { module: "ManyElements", group: "viewHtml", count: 1024, value: "viewHtml1024" }
114+ , { module: "ManyElements", group: "viewHtml", count: 2048, value: "viewHtml2048" }
115+ , { module: "ManyElements", group: "viewHtml", count: 24, value: "viewHtml24" }
116+ , { module: "ManyElements", group: "viewHtml", count: 4096, value: "viewHtml4096" }
117+ , { module: "ManyElements", group: "viewHtml", count: 8192, value: "viewHtml8192" }
118+ , { module: "ManyElements", group: "viewInline", count: 1024, value: "viewInline1024" }
119+ , { module: "ManyElements", group: "viewInline", count: 2048, value: "viewInline2048" }
120+ , { module: "ManyElements", group: "viewInline", count: 24, value: "viewInline24" }
121+ , { module: "ManyElements", group: "viewInline", count: 4096, value: "viewInline4096" }
122+ , { module: "ManyElements", group: "viewInline", count: 8192, value: "viewInline8192" }
123+ ]
124+
125+
126+ var dir = "tmp"
127+ if (!fs.existsSync(dir)) {
128+ fs.mkdirSync(dir);
129+ }
130+
131+ var dir = "./benchmarks/tmp"
132+ if (!fs.existsSync(dir)) {
133+ fs.mkdirSync(dir);
134+ }
135+
136+ var allResults = []
137+ const resultsDir = "benchmarks/results"
138+ const resultName = "1.2-cand"
139+
140+ if (!fs.existsSync(`./${resultsDir}/${resultName}/instances/`)) {
141+ fs.mkdirSync(`./${resultsDir}/${resultName}/instances/`, { recursive: true });
142+ }
143+
144+ console.log(`Beginning benchmark for ${resultName} →`)
145+
146+ for (var i = 0; i < instances.length; i++) {
147+ var item = instances[i]
148+ write_entrypoint(item)
149+ const test_file = `${resultsDir}/${resultName}/instances/${item.value}.html`
150+ var template = fs.readFileSync("./benchmarks/runtime/template/run.html")
151+ var cssom = fs.readFileSync("./experiments/virtual-css/cssom.js")
152+ // we embed the compiled js to avoid having to start a server to read the app.
153+ await compileToString(["tmp/Main.elm"], { optimize: true, cwd: "./benchmarks" }).then(function (compiled_elm_code) {
154+ const compiled = eval(`\`${template}\``)
155+ fs.writeFileSync(test_file, compiled)
156+ });
157+
158+ const page = await browser.newPage();
159+ const results = await benchPage(page, test_file);
160+ results.group = item.group
161+ results.count = item.count
162+ await page.close()
163+ // console.log(results)
164+ console.log(" Benchmark of " + chalk.green(`${item.module}.${item.value}`) + " complete")
165+ allResults.push(results)
166+ }
167+ await browser.close();
168+
169+ allResults = regroupResults(allResults)
170+
171+ writeResults(allResults, resultsDir, resultName)
172+ console.log()
173+ console.log("Benchmark complete")
174+ console.log(" → " + chalk.green(`${resultsDir}/${resultName}/index.html`))
175+
176+})();
deps/elm-ui/benchmarks/runtime/template/run.htmlnew file+57
@@ -0,0 +1,57 @@
1+<!DOCTYPE HTML>
2+<html>
3+<head>
4+ <meta charset="UTF-8">
5+ <title>Main</title>
6+ <script>
7+ ${cssom}
8+ </script>
9+ <script>
10+ ${compiled_elm_code}
11+ </script>
12+ <style>
13+ .box {
14+ width: 400px;
15+ height: 50px;
16+ border: solid thick;
17+ }
18+ .pink {
19+ background-color: pink;
20+ }
21+ .white {
22+ background-color: white;
23+ }
24+ .contain {
25+ contain: strict;
26+ }
27+ </style>
28+</head>
29+
30+<body>
31+ <div id="elm"></div>
32+ <script>
33+ var app = Elm.Main.init({
34+ node: document.getElementById('elm')
35+ });
36+
37+ window.metrics = []
38+ app.ports.elmToWorld.subscribe(function(fromElm){
39+ window.metrics = fromElm
40+ })
41+
42+ function elmRefresh(){
43+ app.ports.worldToElm.send({tag: "Refresh"})
44+ }
45+ function elmStartAnim(){
46+ app.ports.worldToElm.send({tag: "StartAnim"})
47+ }
48+ function elmStopAnim(){
49+ app.ports.worldToElm.send({tag: "StopAnim"})
50+ }
51+ window.elmRefresh = elmRefresh;
52+ window.elmStartAnim = elmStartAnim;
53+ window.elmStopAnim = elmStopAnim;
54+
55+ </script>
56+</body>
57+</html>
deps/elm-ui/benchmarks/runtime/template/viewResults.htmlnew file+24
@@ -0,0 +1,24 @@
1+<!DOCTYPE HTML>
2+<html>
3+<head>
4+ <meta charset="UTF-8">
5+ <title>Results</title>
6+ <script>
7+ ${compiled_elm_code}
8+ </script>
9+</head>
10+
11+<body>
12+ <div id="elm"></div>
13+ <script>
14+ const results = ${results}
15+
16+ var app = Elm.View.Results.init({
17+ node: document.getElementById('elm')
18+ });
19+
20+ app.ports.worldToElm.send(results)
21+
22+ </script>
23+</body>
24+</html>
deps/elm-ui/benchmarks/src/Baseline.elmnew file+31
@@ -0,0 +1,31 @@
1+module Baseline exposing (bench)
2+
3+{-| -}
4+
5+import Benchmark.Render
6+import Html
7+
8+
9+type Msg
10+ = Refresh
11+ | Tick Float
12+
13+
14+bench : Benchmark.Render.Benchmark Int Msg
15+bench =
16+ { name = "Baseline"
17+ , init = 0
18+ , view =
19+ \i ->
20+ Html.text (String.fromInt i)
21+ , update =
22+ \msg model ->
23+ case msg of
24+ Refresh ->
25+ model + 1
26+
27+ Tick i ->
28+ model + 1
29+ , tick = Tick
30+ , refresh = Refresh
31+ }
deps/elm-ui/benchmarks/src/Benchmark/Render.elmnew file+148
@@ -0,0 +1,148 @@
1+port module Benchmark.Render exposing (Benchmark, toProgram)
2+
3+{-| This is the rendering harness. The actual cases are in `src`.
4+-}
5+
6+import Browser
7+import Browser.Events
8+import Html exposing (Html)
9+import Html.Attributes as Attr
10+import Html.Events as Events
11+import Json.Decode as Decode
12+import Json.Encode as Encode
13+import Time
14+
15+
16+type alias Benchmark model msg =
17+ { name : String
18+ , init : model
19+ , view : model -> Html Msg
20+ , update : msg -> model -> model
21+ , tick : Float -> msg
22+ , refresh : msg
23+ }
24+
25+
26+type alias Model model =
27+ { model : model
28+ , animating : Bool
29+ , frames : List Float
30+ }
31+
32+
33+type Msg
34+ = Tick Float
35+ | Refresh
36+ | Received Encode.Value
37+ | StartAnim
38+ | StopAnim
39+
40+
41+toProgram : Benchmark model msg -> Program () (Model model) Msg
42+toProgram render =
43+ Browser.document
44+ { init =
45+ \() ->
46+ ( { model = render.init
47+ , animating = False
48+ , frames = []
49+ }
50+ , Cmd.none
51+ )
52+ , view =
53+ \model ->
54+ { title = render.name
55+ , body =
56+ [ Html.div
57+ [ Attr.style "display" "flex"
58+ , Attr.style "flex-direction" "row"
59+ ]
60+ [ Html.button [ Events.onClick Refresh ] [ Html.text "Refresh" ]
61+ , Html.button [ Events.onClick StartAnim ] [ Html.text "StartAnim" ]
62+ , Html.button [ Events.onClick StopAnim ] [ Html.text "StopAnim" ]
63+ ]
64+ , render.view model.model
65+ ]
66+ }
67+ , update =
68+ update render
69+ , subscriptions =
70+ \model ->
71+ Sub.batch
72+ [ worldToElm Received
73+ , if model.animating then
74+ Browser.Events.onAnimationFrameDelta Tick
75+
76+ else
77+ Sub.none
78+ ]
79+ }
80+
81+
82+update : Benchmark model msg -> Msg -> Model model -> ( Model model, Cmd Msg )
83+update render msg model =
84+ case msg of
85+ StartAnim ->
86+ ( { model | animating = True }
87+ , Cmd.none
88+ )
89+
90+ StopAnim ->
91+ ( { model | animating = False }
92+ , elmToWorld (encodeMetrics render.name model.frames)
93+ )
94+
95+ Refresh ->
96+ ( { model | model = render.update render.refresh model.model }
97+ , Cmd.none
98+ )
99+
100+ Tick time ->
101+ ( { model
102+ | model = render.update (render.tick time) model.model
103+ , frames = time :: model.frames
104+ }
105+ , Cmd.none
106+ )
107+
108+ Received json ->
109+ case Decode.decodeValue outsideMsg json of
110+ Err err ->
111+ ( model, Cmd.none )
112+
113+ Ok newMsg ->
114+ update render newMsg model
115+
116+
117+outsideMsg =
118+ Decode.field "tag" Decode.string
119+ |> Decode.andThen
120+ (\tag ->
121+ case tag of
122+ "Refresh" ->
123+ Decode.succeed Refresh
124+
125+ "StartAnim" ->
126+ Decode.succeed StartAnim
127+
128+ "StopAnim" ->
129+ Decode.succeed StopAnim
130+
131+ _ ->
132+ Decode.fail "Unknown incoming msg"
133+ )
134+
135+
136+encodeMetrics name frames =
137+ Encode.object
138+ [ ( "name", Encode.string name )
139+ , ( "frames"
140+ , Encode.list Encode.float frames
141+ )
142+ ]
143+
144+
145+port worldToElm : (Encode.Value -> msg) -> Sub msg
146+
147+
148+port elmToWorld : Encode.Value -> Cmd msg
deps/elm-ui/benchmarks/src/Contain.elmnew file+159
@@ -0,0 +1,159 @@
1+module Contain exposing
2+ ( viewHtml8192
3+ , viewHtmlContain8192
4+ )
5+
6+{-| -}
7+
8+import Benchmark.Render
9+import Element exposing (..)
10+import Element.Background as Background
11+import Element.Font as Font
12+import Element.Keyed
13+import Html
14+import Html.Attributes
15+import Internal.Model as Internal
16+
17+
18+type alias Model =
19+ { index : Int
20+ , numberOfElements : Int
21+ , elements : List Int
22+ }
23+
24+
25+type Msg
26+ = Refresh
27+ | Tick Float
28+
29+
30+viewHtml8192 : Benchmark.Render.Benchmark Model Msg
31+viewHtml8192 =
32+ viewHtml "viewHtml8192" 8192
33+
34+
35+viewHtmlContain8192 : Benchmark.Render.Benchmark Model Msg
36+viewHtmlContain8192 =
37+ viewHtmlContain "viewHtmlContain8192" 8192
38+
39+
40+white =
41+ rgb 1 1 1
42+
43+
44+pink =
45+ rgb255 240 0 245
46+
47+
48+{-| -}
49+viewHtml : String -> Int -> Benchmark.Render.Benchmark Model Msg
50+viewHtml name count =
51+ { name = name
52+ , init =
53+ { index = 0
54+ , numberOfElements = count
55+ , elements = List.range 0 (count - 1)
56+ }
57+ , view =
58+ \model ->
59+ Html.div []
60+ [ Html.div []
61+ (List.map (viewHtmlElement model.index) model.elements)
62+ ]
63+ , update =
64+ \msg model ->
65+ case msg of
66+ Refresh ->
67+ if model.index > model.numberOfElements then
68+ { model | index = 0 }
69+
70+ else
71+ { model | index = model.index + 1 }
72+
73+ Tick i ->
74+ if model.index > model.numberOfElements then
75+ { model | index = 0 }
76+
77+ else
78+ { model | index = model.index + 1 }
79+ , tick = Tick
80+ , refresh = Refresh
81+ }
82+
83+
84+viewHtmlElement selectedIndex index =
85+ Html.div
86+ [ Html.Attributes.class "box"
87+ , Html.Attributes.class
88+ (if selectedIndex == index then
89+ "white"
90+
91+ else
92+ "pink"
93+ )
94+ ]
95+ [ Html.div []
96+ [ if selectedIndex == index then
97+ Html.text "selected"
98+
99+ else
100+ Html.text "Hello!"
101+ ]
102+ ]
103+
104+
105+{-| -}
106+viewHtmlContain : String -> Int -> Benchmark.Render.Benchmark Model Msg
107+viewHtmlContain name count =
108+ { name = name
109+ , init =
110+ { index = 0
111+ , numberOfElements = count
112+ , elements = List.range 0 (count - 1)
113+ }
114+ , view =
115+ \model ->
116+ Html.div []
117+ [ Html.div []
118+ (List.map (viewHtmlElementContain model.index) model.elements)
119+ ]
120+ , update =
121+ \msg model ->
122+ case msg of
123+ Refresh ->
124+ if model.index > model.numberOfElements then
125+ { model | index = 0 }
126+
127+ else
128+ { model | index = model.index + 1 }
129+
130+ Tick i ->
131+ if model.index > model.numberOfElements then
132+ { model | index = 0 }
133+
134+ else
135+ { model | index = model.index + 1 }
136+ , tick = Tick
137+ , refresh = Refresh
138+ }
139+
140+
141+viewHtmlElementContain selectedIndex index =
142+ Html.div
143+ [ Html.Attributes.class "box contain"
144+ , Html.Attributes.class
145+ (if selectedIndex == index then
146+ "white"
147+
148+ else
149+ "pink"
150+ )
151+ ]
152+ [ Html.div []
153+ [ if selectedIndex == index then
154+ Html.text "selected"
155+
156+ else
157+ Html.text "Hello!"
158+ ]
159+ ]
deps/elm-ui/benchmarks/src/ManyElements.elmnew file+516
@@ -0,0 +1,516 @@
1+module ManyElements exposing
2+ ( elmUI1024
3+ , elmUI128
4+ , elmUI2048
5+ , elmUI24
6+ , elmUI256
7+ , elmUI4096
8+ , elmUI512
9+ , elmUI64
10+ , elmUI8192
11+ , elmUIVCSS1024
12+ , elmUIVCSS128
13+ , elmUIVCSS2048
14+ , elmUIVCSS24
15+ , elmUIVCSS256
16+ , elmUIVCSS4096
17+ , elmUIVCSS512
18+ , elmUIVCSS64
19+ , elmUIVCSS8192
20+ , viewHtml1024
21+ , viewHtml128
22+ , viewHtml2048
23+ , viewHtml24
24+ , viewHtml256
25+ , viewHtml4096
26+ , viewHtml512
27+ , viewHtml64
28+ , viewHtml8192
29+ , viewInline1024
30+ , viewInline128
31+ , viewInline2048
32+ , viewInline24
33+ , viewInline256
34+ , viewInline4096
35+ , viewInline512
36+ , viewInline64
37+ , viewInline8192
38+ )
39+
40+{-| -}
41+
42+import Benchmark.Render
43+import Element exposing (..)
44+import Element.Background as Background
45+import Element.Font as Font
46+import Element.Keyed
47+import Html
48+import Html.Attributes
49+import Internal.Model as Internal
50+
51+
52+
53+{- START BENCHMARKS -}
54+
55+
56+elmUI24 : Benchmark.Render.Benchmark Model Msg
57+elmUI24 =
58+ elmUI "elmUI24" 24
59+
60+
61+elmUI64 : Benchmark.Render.Benchmark Model Msg
62+elmUI64 =
63+ elmUI "elmUI64" 64
64+
65+
66+elmUI128 : Benchmark.Render.Benchmark Model Msg
67+elmUI128 =
68+ elmUI "elmUI128" 128
69+
70+
71+elmUI256 : Benchmark.Render.Benchmark Model Msg
72+elmUI256 =
73+ elmUI "elmUI256" 256
74+
75+
76+elmUI512 : Benchmark.Render.Benchmark Model Msg
77+elmUI512 =
78+ elmUI "elmUI512" 512
79+
80+
81+elmUI1024 : Benchmark.Render.Benchmark Model Msg
82+elmUI1024 =
83+ elmUI "elmUI1024" 1024
84+
85+
86+elmUI2048 : Benchmark.Render.Benchmark Model Msg
87+elmUI2048 =
88+ elmUI "elmUI2048" 2048
89+
90+
91+elmUI4096 : Benchmark.Render.Benchmark Model Msg
92+elmUI4096 =
93+ elmUI "elmUI4096" 4096
94+
95+
96+elmUI8192 : Benchmark.Render.Benchmark Model Msg
97+elmUI8192 =
98+ elmUI "elmUI8192" 8192
99+
100+
101+
102+{- Elm UI VirtualCSS -}
103+
104+
105+elmUIVCSS24 : Benchmark.Render.Benchmark Model Msg
106+elmUIVCSS24 =
107+ elmUIVCSS "elmUIVCSS24" 24
108+
109+
110+elmUIVCSS64 : Benchmark.Render.Benchmark Model Msg
111+elmUIVCSS64 =
112+ elmUIVCSS "elmUIVCSS64" 64
113+
114+
115+elmUIVCSS128 : Benchmark.Render.Benchmark Model Msg
116+elmUIVCSS128 =
117+ elmUIVCSS "elmUIVCSS128" 128
118+
119+
120+elmUIVCSS256 : Benchmark.Render.Benchmark Model Msg
121+elmUIVCSS256 =
122+ elmUIVCSS "elmUIVCSS256" 256
123+
124+
125+elmUIVCSS512 : Benchmark.Render.Benchmark Model Msg
126+elmUIVCSS512 =
127+ elmUIVCSS "elmUIVCSS512" 512
128+
129+
130+elmUIVCSS1024 : Benchmark.Render.Benchmark Model Msg
131+elmUIVCSS1024 =
132+ elmUIVCSS "elmUIVCSS1024" 1024
133+
134+
135+elmUIVCSS2048 : Benchmark.Render.Benchmark Model Msg
136+elmUIVCSS2048 =
137+ elmUIVCSS "elmUIVCSS2048" 2048
138+
139+
140+elmUIVCSS4096 : Benchmark.Render.Benchmark Model Msg
141+elmUIVCSS4096 =
142+ elmUIVCSS "elmUIVCSS4096" 4096
143+
144+
145+elmUIVCSS8192 : Benchmark.Render.Benchmark Model Msg
146+elmUIVCSS8192 =
147+ elmUIVCSS "elmUIVCSS8192" 8192
148+
149+
150+
151+{- Normal Html -}
152+
153+
154+viewHtml24 : Benchmark.Render.Benchmark Model Msg
155+viewHtml24 =
156+ viewHtml "viewHtml24" 24
157+
158+
159+viewHtml64 : Benchmark.Render.Benchmark Model Msg
160+viewHtml64 =
161+ viewHtml "viewHtml64" 64
162+
163+
164+viewHtml128 : Benchmark.Render.Benchmark Model Msg
165+viewHtml128 =
166+ viewHtml "viewHtml128" 128
167+
168+
169+viewHtml256 : Benchmark.Render.Benchmark Model Msg
170+viewHtml256 =
171+ viewHtml "viewHtml256" 256
172+
173+
174+viewHtml512 : Benchmark.Render.Benchmark Model Msg
175+viewHtml512 =
176+ viewHtml "viewHtml512" 512
177+
178+
179+viewHtml1024 : Benchmark.Render.Benchmark Model Msg
180+viewHtml1024 =
181+ viewHtml "viewHtml1024" 1024
182+
183+
184+viewHtml2048 : Benchmark.Render.Benchmark Model Msg
185+viewHtml2048 =
186+ viewHtml "viewHtml2048" 2048
187+
188+
189+viewHtml4096 : Benchmark.Render.Benchmark Model Msg
190+viewHtml4096 =
191+ viewHtml "viewHtml4096" 4096
192+
193+
194+viewHtml8192 : Benchmark.Render.Benchmark Model Msg
195+viewHtml8192 =
196+ viewHtml "viewHtml8192" 8192
197+
198+
199+
200+{- Inline Html -}
201+
202+
203+viewInline24 : Benchmark.Render.Benchmark Model Msg
204+viewInline24 =
205+ viewInline "viewInline24" 24
206+
207+
208+viewInline64 : Benchmark.Render.Benchmark Model Msg
209+viewInline64 =
210+ viewInline "viewInline64" 64
211+
212+
213+viewInline128 : Benchmark.Render.Benchmark Model Msg
214+viewInline128 =
215+ viewInline "viewInline128" 128
216+
217+
218+viewInline256 : Benchmark.Render.Benchmark Model Msg
219+viewInline256 =
220+ viewInline "viewInline256" 256
221+
222+
223+viewInline512 : Benchmark.Render.Benchmark Model Msg
224+viewInline512 =
225+ viewInline "viewInline512" 512
226+
227+
228+viewInline1024 : Benchmark.Render.Benchmark Model Msg
229+viewInline1024 =
230+ viewInline "viewInline1024" 1024
231+
232+
233+viewInline2048 : Benchmark.Render.Benchmark Model Msg
234+viewInline2048 =
235+ viewInline "viewInline2048" 2048
236+
237+
238+viewInline4096 : Benchmark.Render.Benchmark Model Msg
239+viewInline4096 =
240+ viewInline "viewInline4096" 4096
241+
242+
243+viewInline8192 : Benchmark.Render.Benchmark Model Msg
244+viewInline8192 =
245+ viewInline "viewInline8192" 8192
246+
247+
248+
249+{- END BENCHMARKS -}
250+
251+
252+type alias Model =
253+ { index : Int
254+ , numberOfElements : Int
255+ , elements : List Int
256+ }
257+
258+
259+type Msg
260+ = Refresh
261+ | Tick Float
262+
263+
264+{-| -}
265+elmUIVCSS : String -> Int -> Benchmark.Render.Benchmark Model Msg
266+elmUIVCSS name count =
267+ { name = name
268+ , init =
269+ { index = 0
270+ , numberOfElements = count
271+ , elements = List.range 0 (count - 1)
272+ }
273+ , view =
274+ \model ->
275+ Element.layoutWith
276+ { options =
277+ [ Internal.RenderModeOption
278+ Internal.WithVirtualCss
279+ ]
280+ }
281+ []
282+ (Element.column [ spacing 8, centerX ]
283+ (List.map (viewEl model.index) model.elements)
284+ )
285+ , update =
286+ \msg model ->
287+ case msg of
288+ Refresh ->
289+ if model.index > model.numberOfElements then
290+ { model | index = 0 }
291+
292+ else
293+ { model | index = model.index + 1 }
294+
295+ Tick i ->
296+ if model.index > model.numberOfElements then
297+ { model | index = 0 }
298+
299+ else
300+ { model | index = model.index + 1 }
301+ , tick = Tick
302+ , refresh = Refresh
303+ }
304+
305+
306+{-| -}
307+elmUI : String -> Int -> Benchmark.Render.Benchmark Model Msg
308+elmUI name count =
309+ { name = name
310+ , init =
311+ { index = 0
312+ , numberOfElements = count
313+ , elements = List.range 0 (count - 1)
314+ }
315+ , view =
316+ \model ->
317+ Element.layout []
318+ (Element.column [ spacing 8, centerX ]
319+ (List.map (viewEl model.index) model.elements)
320+ )
321+ , update =
322+ \msg model ->
323+ case msg of
324+ Refresh ->
325+ if model.index > model.numberOfElements then
326+ { model | index = 0 }
327+
328+ else
329+ { model | index = model.index + 1 }
330+
331+ Tick i ->
332+ if model.index > model.numberOfElements then
333+ { model | index = 0 }
334+
335+ else
336+ { model | index = model.index + 1 }
337+ , tick = Tick
338+ , refresh = Refresh
339+ }
340+
341+
342+viewEl selectedIndex index =
343+ el
344+ [ Background.color
345+ (if selectedIndex == index then
346+ pink
347+
348+ else
349+ white
350+ )
351+ , Font.color
352+ (if selectedIndex /= index then
353+ pink
354+
355+ else
356+ white
357+ )
358+ , padding 24
359+ , width (px 500)
360+ , height (px 70)
361+ ]
362+ (if selectedIndex == index then
363+ text "selected"
364+
365+ else
366+ text "Hello!"
367+ )
368+
369+
370+white =
371+ rgb 1 1 1
372+
373+
374+pink =
375+ rgb255 240 0 245
376+
377+
378+pinkish i =
379+ rgb255 (wrap255 (i + 240)) 0 245
380+
381+
382+wrap255 i =
383+ if i > 255 then
384+ 0
385+
386+ else if i < 0 then
387+ 0
388+
389+ else
390+ i
391+
392+
393+{-| -}
394+viewHtml : String -> Int -> Benchmark.Render.Benchmark Model Msg
395+viewHtml name count =
396+ { name = name
397+ , init =
398+ { index = 0
399+ , numberOfElements = count
400+ , elements = List.range 0 (count - 1)
401+ }
402+ , view =
403+ \model ->
404+ Html.div []
405+ [ Html.div []
406+ (List.map (viewHtmlElement model.index) model.elements)
407+ ]
408+ , update =
409+ \msg model ->
410+ case msg of
411+ Refresh ->
412+ if model.index > model.numberOfElements then
413+ { model | index = 0 }
414+
415+ else
416+ { model | index = model.index + 1 }
417+
418+ Tick i ->
419+ if model.index > model.numberOfElements then
420+ { model | index = 0 }
421+
422+ else
423+ { model | index = model.index + 1 }
424+ , tick = Tick
425+ , refresh = Refresh
426+ }
427+
428+
429+viewHtmlElement selectedIndex index =
430+ Html.div
431+ [ Html.Attributes.class
432+ (if selectedIndex == index then
433+ "white"
434+
435+ else
436+ "pink"
437+ )
438+ ]
439+ [ Html.div []
440+ [ if selectedIndex == index then
441+ Html.text "selected"
442+
443+ else
444+ Html.text "Hello!"
445+ ]
446+ ]
447+
448+
449+{-| -}
450+viewInline : String -> Int -> Benchmark.Render.Benchmark Model Msg
451+viewInline name count =
452+ { name = name
453+ , init =
454+ { index = 0
455+ , numberOfElements = count
456+ , elements = List.range 0 (count - 1)
457+ }
458+ , view =
459+ \model ->
460+ Html.div []
461+ [ Html.div []
462+ (List.map (viewInlineHtmlElement model.index) model.elements)
463+ ]
464+ , update =
465+ \msg model ->
466+ case msg of
467+ Refresh ->
468+ if model.index > model.numberOfElements then
469+ { model | index = 0 }
470+
471+ else
472+ { model | index = model.index + 1 }
473+
474+ Tick i ->
475+ if model.index > model.numberOfElements then
476+ { model | index = 0 }
477+
478+ else
479+ { model | index = model.index + 1 }
480+ , tick = Tick
481+ , refresh = Refresh
482+ }
483+
484+
485+viewInlineHtmlElement selectedIndex index =
486+ Html.div
487+ (if selectedIndex == index then
488+ [ Html.Attributes.style "background-color" (renderColor (wrap255 (index + 240)) 0 245)
489+ , Html.Attributes.style "color" "white"
490+ , Html.Attributes.style "padding" "24"
491+ ]
492+
493+ else
494+ [ Html.Attributes.style "background-color" "white"
495+ , Html.Attributes.style "color" (renderColor (wrap255 (index + 240)) 0 245)
496+ , Html.Attributes.style "padding" "24"
497+ ]
498+ )
499+ [ Html.div []
500+ [ if selectedIndex == index then
501+ Html.text "selected"
502+
503+ else
504+ Html.text "Hello!"
505+ ]
506+ ]
507+
508+
509+renderColor r g b =
510+ "rgb("
511+ ++ String.fromInt r
512+ ++ ","
513+ ++ String.fromInt g
514+ ++ ","
515+ ++ String.fromInt b
516+ ++ ")"
deps/elm-ui/benchmarks/src/View/Results.elmnew file+379
@@ -0,0 +1,379 @@
1+port module View.Results exposing (main)
2+
3+import Browser
4+import Color
5+import Html
6+import Html.Attributes as Attr exposing (class)
7+import LineChart as LineChart
8+import LineChart.Area as Area
9+import LineChart.Axis as Axis
10+import LineChart.Axis.Intersection as Intersection
11+import LineChart.Axis.Line as AxisLine
12+import LineChart.Axis.Range as Range
13+import LineChart.Axis.Ticks as Ticks
14+import LineChart.Axis.Title as Title
15+import LineChart.Colors as Colors
16+import LineChart.Container as Container
17+import LineChart.Dots as Dots
18+import LineChart.Events as Events
19+import LineChart.Grid as Grid
20+import LineChart.Interpolation as Interpolation
21+import LineChart.Junk as Junk exposing (..)
22+import LineChart.Legends as Legends
23+import LineChart.Line as Line
24+
25+
26+row children =
27+ Html.div
28+ [ Attr.style "display" "flex"
29+ , Attr.style "flex-direction" "row"
30+ ]
31+ children
32+
33+
34+column children =
35+ Html.div
36+ [ Attr.style "display" "flex"
37+ , Attr.style "flex-direction" "column"
38+ ]
39+ children
40+
41+
42+main =
43+ Browser.document
44+ { init =
45+ \() ->
46+ ( { data = [] }
47+ , Cmd.none
48+ )
49+ , view =
50+ \model ->
51+ { title = "Results"
52+ , body =
53+ [ Html.div
54+ [ class "container" ]
55+ [ column
56+ [ Html.h2 [] [ Html.text "Benchmarked Pages" ]
57+ , row (List.map viewLinks model.data)
58+ ]
59+ , row
60+ [ -- viewNodes model.data
61+ viewFps model.data
62+ , viewTimeToPaint model.data
63+ ]
64+ , row
65+ [ column
66+ (List.map
67+ (\data ->
68+ viewRenderBreakdown
69+ { get = .coldRender
70+ , getCount = .count
71+ , name = data.name
72+ , flavor = "Cold render"
73+ , range = ( 0, 1.2 )
74+ }
75+ (List.sortBy .count data.results)
76+ )
77+ model.data
78+ )
79+ , column
80+ (List.map
81+ (\data ->
82+ viewRenderBreakdown
83+ { get = .warmRender
84+ , getCount = .count
85+ , name = data.name
86+ , flavor = "Warm render"
87+ , range = ( 0, 1.2 )
88+ }
89+ (List.sortBy .count data.results)
90+ )
91+ model.data
92+ )
93+ , column
94+ (List.map
95+ (\data ->
96+ viewRenderBreakdown
97+ { get = .extendedRender
98+ , getCount = .count
99+ , name = data.name
100+ , flavor = "Long Animation"
101+ , range = ( 0, 5 )
102+ }
103+ (List.sortBy .count data.results)
104+ )
105+ model.data
106+ )
107+ ]
108+ ]
109+ ]
110+ }
111+ , update =
112+ update
113+ , subscriptions =
114+ \model ->
115+ Sub.batch
116+ [ worldToElm Received
117+ ]
118+ }
119+
120+
121+type Msg
122+ = Received (List Data)
123+
124+
125+update : Msg -> Model -> ( Model, Cmd Msg )
126+update msg model =
127+ case msg of
128+ Received data ->
129+ ( { data = data }, Cmd.none )
130+
131+
132+viewLinks data =
133+ column
134+ (Html.h1 [] [ Html.text data.name ]
135+ :: (data.results
136+ |> List.sortBy .link
137+ |> List.map viewSingleLink
138+ )
139+ )
140+
141+
142+viewSingleLink result =
143+ Html.a
144+ [ Attr.href result.link
145+ , Attr.style "padding-right" "30px"
146+ ]
147+ [ Html.text result.name ]
148+
149+
150+
151+-- DATA
152+
153+
154+port worldToElm : (List Data -> msg) -> Sub msg
155+
156+
157+type alias Model =
158+ { data : List Data }
159+
160+
161+type alias Data =
162+ { name : String
163+ , results : List Render
164+ }
165+
166+
167+type alias Render =
168+ { name : String
169+ , count : Float
170+ , fps : Float
171+ , timeToFirstPaintMS : Float
172+ , nodes : Float
173+ , link : String
174+ , coldRender :
175+ Breakdown
176+ , warmRender :
177+ Breakdown
178+ , extendedRender :
179+ Breakdown
180+ }
181+
182+
183+type alias Breakdown =
184+ { layoutSeconds : Float
185+ , recalcStyleSeconds : Float
186+ , scriptDurationSeconds : Float
187+ }
188+
189+
190+
191+-- Different Views
192+
193+
194+getColor i =
195+ case i of
196+ 0 ->
197+ Colors.green
198+
199+ 1 ->
200+ Colors.blue
201+
202+ 2 ->
203+ Colors.pink
204+
205+ _ ->
206+ Colors.gold
207+
208+
209+getShape i =
210+ Dots.triangle
211+
212+
213+graphWidth =
214+ 800
215+
216+
217+graphHeight =
218+ 500
219+
220+
221+container =
222+ Container.styled "line-chart-1"
223+ [ ( "font-family", "monospace" )
224+ , ( "flex-shrink", "0" )
225+ ]
226+
227+
228+viewFps : List Data -> Html.Html msg
229+viewFps datums =
230+ LineChart.viewCustom
231+ { y = Axis.default graphHeight "FPS" .fps
232+ , x = Axis.default graphWidth "Base Count" .count
233+ , container = container
234+ , interpolation =
235+ -- Try out these different configs!
236+ -- Interpolation.linear
237+ Interpolation.monotone
238+
239+ -- Interpolation.stepped
240+ , intersection = Intersection.default
241+ , legends = Legends.default
242+ , events = Events.default
243+ , junk = Junk.default
244+ , grid = Grid.default
245+ , area = Area.default
246+ , line = Line.default
247+ , dots = Dots.default
248+ }
249+ (List.indexedMap viewResult datums)
250+
251+
252+viewResult i data =
253+ LineChart.line (getColor i) (getShape i) data.name (List.sortBy .count data.results)
254+
255+
256+viewTimeToPaint : List Data -> Html.Html msg
257+viewTimeToPaint datums =
258+ LineChart.viewCustom
259+ { y = Axis.default graphHeight "First Paint" (max 0 << .timeToFirstPaintMS)
260+ , x = Axis.default graphWidth "Base Count" .count
261+ , container = container
262+ , interpolation =
263+ -- Try out these different configs!
264+ -- Interpolation.linear
265+ Interpolation.monotone
266+
267+ -- Interpolation.stepped
268+ , intersection = Intersection.default
269+ , legends = Legends.default
270+ , events = Events.default
271+ , junk = Junk.default
272+ , grid = Grid.default
273+ , area = Area.default
274+ , line = Line.default
275+ , dots = Dots.default
276+ }
277+ (List.indexedMap viewResult datums)
278+
279+
280+viewNodes : List Data -> Html.Html msg
281+viewNodes datums =
282+ LineChart.viewCustom
283+ { y = Axis.default graphHeight "Nodes" .nodes
284+ , x = Axis.default graphWidth "Base Count" .count
285+ , container = container
286+ , interpolation =
287+ -- Try out these different configs!
288+ -- Interpolation.linear
289+ Interpolation.monotone
290+
291+ -- Interpolation.stepped
292+ , intersection = Intersection.default
293+ , legends = Legends.default
294+ , events = Events.default
295+ , junk = Junk.default
296+ , grid = Grid.default
297+ , area = Area.default
298+ , line = Line.default
299+ , dots = Dots.default
300+ }
301+ (List.indexedMap viewResult datums)
302+
303+
304+viewRenderBreakdown :
305+ { get : Render -> Breakdown
306+ , getCount : Render -> Float
307+ , name : String
308+ , flavor : String
309+ , range : ( Float, Float )
310+ }
311+ -> List Render
312+ -> Html.Html msg
313+viewRenderBreakdown { get, getCount, name, flavor, range } results =
314+ Html.div []
315+ [ Html.h2 [] [ Html.text (name ++ ", " ++ flavor) ]
316+ , LineChart.viewCustom
317+ { y =
318+ Axis.custom
319+ { title = Title.default (name ++ "(s)")
320+ , variable = Just << .seconds
321+ , pixels = graphHeight
322+ , range = Range.window (Tuple.first range) (Tuple.second range)
323+ , axisLine = AxisLine.full Colors.black
324+ , ticks = Ticks.default
325+ }
326+ , x = Axis.default graphWidth "Base Count" .count
327+ , container = container
328+ , interpolation =
329+ -- Try out these different configs!
330+ -- Interpolation.linear
331+ Interpolation.monotone
332+
333+ -- Interpolation.stepped
334+ , intersection = Intersection.default
335+ , legends = Legends.default
336+ , events = Events.default
337+ , junk = Junk.default
338+ , grid = Grid.default
339+ , area = Area.stacked 0.5
340+ , line = Line.default
341+ , dots = Dots.default
342+ }
343+ [ LineChart.line (getColor 0)
344+ (getShape 0)
345+ "Layout"
346+ (List.map
347+ (\x ->
348+ { seconds = .layoutSeconds (get x)
349+ , count = getCount x
350+ }
351+ )
352+ results
353+ )
354+ , LineChart.line (getColor 1)
355+ (getShape 1)
356+ "RecalcStyle"
357+ (List.map
358+ (\x ->
359+ { seconds =
360+ .recalcStyleSeconds (get x)
361+ , count = getCount x
362+ }
363+ )
364+ results
365+ )
366+ , LineChart.line (getColor 2)
367+ (getShape 2)
368+ "Script"
369+ (List.map
370+ (\x ->
371+ { seconds =
372+ .scriptDurationSeconds (get x)
373+ , count = getCount x
374+ }
375+ )
376+ results
377+ )
378+ ]
379+ ]
deps/elm-ui/elm.jsonnew file+28
@@ -0,0 +1,28 @@
1+{
2+ "type": "package",
3+ "name": "mdgriffith/elm-ui",
4+ "summary": "Layout and style that's easy to refactor, all without thinking about CSS.",
5+ "license": "BSD-3-Clause",
6+ "version": "1.1.8",
7+ "exposed-modules": [
8+ "Element",
9+ "Element.Input",
10+ "Element.Events",
11+ "Element.Background",
12+ "Element.Border",
13+ "Element.Font",
14+ "Element.Lazy",
15+ "Element.Keyed",
16+ "Element.Region"
17+ ],
18+ "elm-version": "0.19.0 <= v < 0.20.0",
19+ "dependencies": {
20+ "elm/core": "1.0.0 <= v < 2.0.0",
21+ "elm/html": "1.0.0 <= v < 2.0.0",
22+ "elm/json": "1.0.0 <= v < 2.0.0",
23+ "elm/virtual-dom": "1.0.0 <= v < 2.0.0"
24+ },
25+ "test-dependencies": {
26+ "elm-explorations/test": "1.2.2 <= v < 2.0.0"
27+ }
28+}
deps/elm-ui/examples/Basic.elmnew file+29
@@ -0,0 +1,29 @@
1+module Basic exposing (..)
2+
3+{-| -}
4+
5+import Element exposing (..)
6+import Element.Background as Background
7+import Element.Font as Font
8+import Element.Input
9+import Element.Lazy
10+
11+
12+main =
13+ Element.layout
14+ [ Background.color (rgba 0 0 0 1)
15+ , Font.color (rgba 1 1 1 1)
16+ , Font.italic
17+ , Font.size 32
18+ , Font.family
19+ [ Font.external
20+ { url = "https://fonts.googleapis.com/css?family=EB+Garamond"
21+ , name = "EB Garamond"
22+ }
23+ , Font.sansSerif
24+ ]
25+ ]
26+ <|
27+ el
28+ [ centerX, centerY ]
29+ (text "Hello stylish friend!")
deps/elm-ui/examples/Form.elmnew file+209
@@ -0,0 +1,209 @@
1+module Form exposing (..)
2+
3+{-| -}
4+
5+import Browser
6+import Element exposing (..)
7+import Element.Background as Background
8+import Element.Border as Border
9+import Element.Font as Font
10+import Element.Input as Input
11+import Element.Region as Region
12+
13+
14+white =
15+ Element.rgb 1 1 1
16+
17+
18+grey =
19+ Element.rgb 0.9 0.9 0.9
20+
21+
22+blue =
23+ Element.rgb 0 0 0.8
24+
25+
26+red =
27+ Element.rgb 0.8 0 0
28+
29+
30+darkBlue =
31+ Element.rgb 0 0 0.9
32+
33+
34+main =
35+ Browser.sandbox
36+ { init = init
37+ , view = view
38+ , update = update
39+ }
40+
41+
42+init =
43+ { username = ""
44+ , password = ""
45+ , agreeTOS = False
46+ , comment = "Extra hot sauce?\n\n\nYes pls"
47+ , lunch = Gyro
48+ , spiciness = 2
49+ }
50+
51+
52+type alias Form =
53+ { username : String
54+ , password : String
55+ , agreeTOS : Bool
56+ , comment : String
57+ , lunch : Lunch
58+ , spiciness : Float
59+ }
60+
61+
62+type Msg
63+ = Update Form
64+
65+
66+update msg model =
67+ case Debug.log "msg" msg of
68+ Update new ->
69+ new
70+
71+
72+type Lunch
73+ = Burrito
74+ | Taco
75+ | Gyro
76+
77+
78+view model =
79+ Element.layout
80+ [ Font.size 20
81+ ]
82+ <|
83+ Element.column
84+ [ width (px 800)
85+ , height shrink
86+ , centerY
87+ , centerX
88+ , spacing 36
89+ , padding 10
90+ ]
91+ [ el
92+ [ Region.heading 1
93+ , alignLeft
94+ , Font.size 36
95+ ]
96+ (text "Welcome to the Stylish Elephants Lunch Emporium")
97+ , Input.radio
98+ [ spacing 12
99+ , Background.color grey
100+ ]
101+ { selected = Just model.lunch
102+ , onChange = \new -> Update { model | lunch = new }
103+ , label = Input.labelAbove [ Font.size 14, paddingXY 0 12 ] (text "What would you like for lunch?")
104+ , options =
105+ [ Input.option Gyro (text "Gyro")
106+ , Input.option Burrito (text "Burrito")
107+ , Input.option Taco (text "Taco")
108+ ]
109+ }
110+ , Input.username
111+ [ spacing 12
112+ , below
113+ (el
114+ [ Font.color red
115+ , Font.size 14
116+ , alignRight
117+ , moveDown 6
118+ ]
119+ (text "This one is wrong")
120+ )
121+ ]
122+ { text = model.username
123+ , placeholder = Just (Input.placeholder [] (text "username"))
124+ , onChange = \new -> Update { model | username = new }
125+ , label = Input.labelAbove [ Font.size 14 ] (text "Username")
126+ }
127+ , Input.currentPassword [ spacing 12 ]
128+ { text = model.password
129+ , placeholder = Nothing
130+ , onChange = \new -> Update { model | password = new }
131+ , label = Input.labelAbove [ Font.size 14 ] (text "Password")
132+ , show = False
133+ }
134+ , Input.multiline
135+ [ height shrink
136+ , spacing 12
137+
138+ -- , padding 6
139+ ]
140+ { text = model.comment
141+ , placeholder = Just (Input.placeholder [] (text "Extra hot sauce?\n\n\nYes pls"))
142+ , onChange = \new -> Update { model | comment = new }
143+ , label = Input.labelAbove [ Font.size 14 ] (text "Leave a comment!")
144+ , spellcheck = False
145+ }
146+ , Input.checkbox []
147+ { checked = model.agreeTOS
148+ , onChange = \new -> Update { model | agreeTOS = new }
149+ , icon = Input.defaultCheckbox
150+ , label = Input.labelRight [] (text "Agree to Terms of Service")
151+ }
152+ , Input.slider
153+ [ Element.height (Element.px 30)
154+ , Element.behindContent
155+ (Element.el
156+ [ Element.width Element.fill
157+ , Element.height (Element.px 2)
158+ , Element.centerY
159+ , Background.color grey
160+ , Border.rounded 2
161+ ]
162+ Element.none
163+ )
164+ ]
165+ { onChange = \new -> Update { model | spiciness = new }
166+ , label = Input.labelAbove [] (text ("Spiciness: " ++ String.fromFloat model.spiciness))
167+ , min = 0
168+ , max = 3.2
169+ , step = Nothing
170+ , value = model.spiciness
171+ , thumb =
172+ Input.defaultThumb
173+ }
174+ , Input.slider
175+ [ Element.width (Element.px 40)
176+ , Element.height (Element.px 200)
177+ , Element.behindContent
178+ (Element.el
179+ [ Element.height Element.fill
180+ , Element.width (Element.px 2)
181+ , Element.centerX
182+ , Background.color grey
183+ , Border.rounded 2
184+ ]
185+ Element.none
186+ )
187+ ]
188+ { onChange = \new -> Update { model | spiciness = new }
189+ , label = Input.labelAbove [] (text ("Spiciness: " ++ String.fromFloat model.spiciness))
190+ , min = 0
191+ , max = 3.2
192+ , step = Nothing
193+ , value = model.spiciness
194+ , thumb =
195+ Input.defaultThumb
196+ }
197+ , Input.button
198+ [ Background.color blue
199+ , Font.color white
200+ , Border.color darkBlue
201+ , paddingXY 32 16
202+ , Border.rounded 3
203+
204+ -- , width fill
205+ ]
206+ { onPress = Nothing
207+ , label = Element.text "Place your lunch order!"
208+ }
209+ ]
deps/elm-ui/examples/Pseudo.elmnew file+31
@@ -0,0 +1,31 @@
1+module Pseudo exposing (..)
2+
3+import Element exposing (..)
4+import Element.Background as Background
5+import Element.Font as Font
6+
7+
8+main =
9+ Element.layout
10+ [ Background.color (rgba 0 0 0 1)
11+ , Font.color (rgba 1 1 1 1)
12+ , Font.italic
13+ , Font.size 32
14+ , Font.family
15+ [ Font.sansSerif ]
16+ ]
17+ <|
18+ column [ centerX, centerY ]
19+ [ el
20+ [ mouseOver [ Background.color <| rgb255 255 0 0 ]
21+ , mouseDown [ Background.color <| rgb255 0 0 255 ]
22+ ]
23+ <|
24+ text "The following priority of pseudo classes is fixed"
25+ , el
26+ [ mouseDown [ Background.color <| rgb255 0 0 255 ]
27+ , mouseOver [ Background.color <| rgb255 255 0 0 ]
28+ ]
29+ <|
30+ text "hover < focused < active"
31+ ]
deps/elm-ui/examples/Table.elmnew file+65
@@ -0,0 +1,65 @@
1+module Table exposing (..)
2+
3+{-| -}
4+
5+import Element exposing (..)
6+import Element.Background as Background
7+import Element.Font as Font
8+import Element.Input
9+import Element.Lazy
10+
11+
12+type alias Person =
13+ { firstName : String
14+ , lastName : String
15+ }
16+
17+
18+persons : List Person
19+persons =
20+ [ { firstName = "David"
21+ , lastName = "Bowie"
22+ }
23+ , { firstName = "Florence"
24+ , lastName = "Welch"
25+ }
26+ ]
27+
28+
29+main =
30+ Element.layout
31+ [ Background.color (rgba 0 0 0 1)
32+ , Font.color (rgba 1 1 1 1)
33+ , Font.italic
34+ , Font.size 32
35+ , Font.family
36+ [ Font.external
37+ { url = "https://fonts.googleapis.com/css?family=EB+Garamond"
38+ , name = "EB Garamond"
39+ }
40+ , Font.sansSerif
41+ ]
42+ ]
43+ <|
44+ Element.table
45+ [ Element.centerX
46+ , Element.centerY
47+ , Element.spacing 5
48+ , Element.padding 10
49+ ]
50+ { data = persons
51+ , columns =
52+ [ { header = Element.text "First Name"
53+ , width = px 200
54+ , view =
55+ \person ->
56+ Element.text person.firstName
57+ }
58+ , { header = Element.text "Last Name"
59+ , width = fill
60+ , view =
61+ \person ->
62+ Element.text person.lastName
63+ }
64+ ]
65+ }
deps/elm-ui/examples/elm.jsonnew file+22
@@ -0,0 +1,22 @@
1+{
2+ "type": "application",
3+ "source-directories": [".", "../src/"],
4+ "elm-version": "0.19.1",
5+ "dependencies": {
6+ "direct": {
7+ "elm/browser": "1.0.0",
8+ "elm/core": "1.0.0",
9+ "elm/html": "1.0.0",
10+ "elm/json": "1.0.0",
11+ "elm/virtual-dom": "1.0.0"
12+ },
13+ "indirect": {
14+ "elm/time": "1.0.0",
15+ "elm/url": "1.0.0"
16+ }
17+ },
18+ "test-dependencies": {
19+ "direct": {},
20+ "indirect": {}
21+ }
22+}
deps/elm-ui/experiments/Accumulator.elmnew file+57
@@ -0,0 +1,57 @@
1+module Accumulation exposing (..)
2+
3+{-| -}
4+
5+import Set
6+
7+
8+type Style
9+ = Color String Float Float Float Float
10+ | Spacing String Float
11+ | Font String (List String)
12+
13+
14+key style =
15+ case style of
16+ Color k _ _ _ _ ->
17+ k
18+
19+ Spacing k _ ->
20+ k
21+
22+ Font k _ ->
23+ k
24+
25+
26+type Element
27+ = Element (List Style) (List Element)
28+ | None
29+
30+
31+render element =
32+ case element of
33+ None ->
34+ []
35+
36+ Element styles children ->
37+ let
38+ childrenStyles =
39+ List.foldr render [] children
40+ in
41+ styles ++ childrenStyles
42+
43+
44+finalize styles =
45+ List.foldl deduplicate ( Set.empty, [] ) styles
46+
47+
48+deduplicate style ( cached, styles ) =
49+ if Set.member (key style) then
50+ ( cached, styles )
51+ else
52+ ( Set.insert (key style), style :: styles )
53+
54+
55+toHtml element =
56+ render element
57+ |> finalize
deps/elm-ui/experiments/font-adjustment-updated/FontAdjustment.elmnew file+545
@@ -0,0 +1,545 @@
1+module Main exposing (main)
2+
3+{-| Line Height as its specified through CSS doesn't make a whole lot of sense typographically.
4+
5+We also run into issues with sizing a font. The font size generally refers to the full type size (from the top of ascendors to the bottom of descenders)
6+
7+However, sometimes we might want to size things from the top of the Capital to the baseline.
8+
9+Or from the top of the x-height to the baseline.
10+
11+The main place this shows up is for dropped capitals, and for text on buttons.
12+
13+-}
14+
15+import Browser
16+import Element exposing (..)
17+import Element.Background as Background
18+import Element.Border as Border
19+import Element.Font as Font
20+import Element.Input as Input
21+import Element.Lazy
22+import Html
23+import Html.Attributes
24+
25+
26+type alias FontAdjustment =
27+ { lineHeight : Float
28+ , capital : Line
29+ , lowercase : Line
30+ , baseline : Line
31+ , descender : Line
32+ }
33+
34+
35+type alias Line =
36+ Float
37+
38+
39+type Msg
40+ = UpdateAdjustment FontAdjustment
41+
42+
43+edges =
44+ { top = 0
45+ , right = 0
46+ , bottom = 0
47+ , left = 0
48+ }
49+
50+
51+garamond =
52+ let
53+ default =
54+ { capital = 1.09
55+ , lowercase = 0.81
56+ , baseline = 0.385
57+ , descender = 0.095
58+ , lineHeight = 1.5
59+ }
60+ in
61+ { adjustment =
62+ default
63+ , converted =
64+ convertAdjustment default
65+ , font =
66+ { url = Just "https://fonts.googleapis.com/css?family=EB+Garamond"
67+ , name = "EB Garamond"
68+ , variants = []
69+ , adjustment =
70+ { capital = default.capital
71+ , lowercase = default.lowercase
72+ , baseline = default.baseline
73+ , descender = default.descender
74+ }
75+ }
76+ }
77+
78+
79+catamaran =
80+ let
81+ default =
82+ { capital = 1.15
83+ , lowercase = 0.96
84+ , baseline = 0.465
85+ , descender = 0.245
86+ , lineHeight = 1.5
87+ }
88+ in
89+ { adjustment =
90+ default
91+ , converted =
92+ convertAdjustment default
93+ , font =
94+ { url = Just "https://fonts.googleapis.com/css?family=Catamaran"
95+ , name = "Catamaran"
96+ , variants = []
97+ , adjustment =
98+ { capital = default.capital
99+ , lowercase = default.lowercase
100+ , baseline = default.baseline
101+ , descender = default.descender
102+ }
103+ }
104+ }
105+
106+
107+poiret =
108+ let
109+ default =
110+ { capital = 1.12
111+ , lowercase = 0.82
112+ , baseline = 0.365
113+ , descender = 0.18
114+ , lineHeight = 1.5
115+ }
116+ in
117+ { adjustment =
118+ default
119+ , converted =
120+ convertAdjustment default
121+ , font =
122+ { url = Just "https://fonts.googleapis.com/css?family=Poiret+One"
123+ , name = "Poiret One"
124+ , variants = []
125+ , adjustment =
126+ { capital = default.capital
127+ , lowercase = default.lowercase
128+ , baseline = default.baseline
129+ , descender = default.descender
130+ }
131+ }
132+ }
133+
134+
135+roboto =
136+ let
137+ default =
138+ { capital = 1.115
139+ , lowercase = 0.93
140+ , baseline = 0.4
141+ , descender = 0.19
142+ , lineHeight = 1.5
143+ }
144+ in
145+ { adjustment =
146+ default
147+ , converted =
148+ convertAdjustment default
149+ , font =
150+ { url = Just "https://fonts.googleapis.com/css?family=Roboto"
151+ , name = "Roboto"
152+ , adjustment =
153+ { capital = default.capital
154+ , lowercase = default.lowercase
155+ , baseline = default.baseline
156+ , descender = default.descender
157+ }
158+ , variants = []
159+ }
160+ }
161+
162+
163+init =
164+ -- catamaran
165+ garamond
166+
167+
168+
169+-- poiret
170+-- roboto
171+
172+
173+update msg model =
174+ case msg of
175+ UpdateAdjustment adj ->
176+ let
177+ font =
178+ model.font
179+ in
180+ { model
181+ | adjustment = adj
182+ , converted = convertAdjustment adj
183+ , font =
184+ { font
185+ | adjustment =
186+ { capital = adj.capital
187+ , lowercase = adj.lowercase
188+ , baseline = adj.baseline
189+ , descender = adj.descender
190+ }
191+ }
192+ }
193+
194+
195+main =
196+ Browser.sandbox
197+ { init = init
198+ , update = update
199+ , view = view
200+ }
201+
202+
203+view model =
204+ Element.layout
205+ [ above (html (Html.node "style" [] [ Html.text """
206+.lh-15 .t {
207+ line-height: 1.5;
208+}
209+
210+.lh-norm .t {
211+ line-height: normal;
212+}
213+
214+ """ ]))
215+ , Background.color (rgba 1 1 1 1)
216+ , padding 100
217+ , Font.color (rgba 0 0 0 1)
218+ , Font.family
219+ [ -- Font.external
220+ -- { url = "https://fonts.googleapis.com/css?family=EB+Garamond"
221+ -- , name = "EB Garamond"
222+ -- }
223+ -- Font.external
224+ -- { url = "https://fonts.googleapis.com/css?family=Catamaran"
225+ -- , name = "Catamaran"
226+ -- }
227+ Font.with
228+ model.font
229+ , Font.sansSerif
230+ ]
231+ ]
232+ <|
233+ column [ width fill, height fill, spacing 128 ]
234+ [ adjustor 120 model.adjustment
235+ , adjusted 120 model.converted
236+ ]
237+
238+
239+style name val =
240+ htmlAttribute (Html.Attributes.style name val)
241+
242+
243+class name =
244+ htmlAttribute (Html.Attributes.class name)
245+
246+
247+charcoal =
248+ rgb 0.7 0.7 0.7
249+
250+
251+adjustor size adjustment =
252+ let
253+ labels =
254+ [ viewAdjustment "Type Height" adjustment.capital size 180 adjustment.lineHeight (\capital -> { adjustment | capital = capital })
255+ , viewAdjustment "Lowercase Height" adjustment.lowercase size 60 adjustment.lineHeight (\lowercase -> { adjustment | lowercase = lowercase })
256+ , viewAdjustment "Baseline" adjustment.baseline size 120 adjustment.lineHeight (\baseline -> { adjustment | baseline = baseline })
257+ , viewAdjustment "Descender" adjustment.descender size 0 adjustment.lineHeight (\descender -> { adjustment | descender = descender })
258+ ]
259+ in
260+ el
261+ ([ centerX
262+ , centerY
263+ , Background.color (rgb 0 0.8 0.9)
264+ , class "lh-15"
265+ , style "line-height" (String.fromFloat adjustment.lineHeight)
266+ , onRight
267+ (el
268+ [ centerY
269+ , width (px 40)
270+
271+ -- , height (px (round (toFloat size * (1 / 1.5))))
272+ , height (px size)
273+ , Background.color (rgb 0.9 0.8 0)
274+ ]
275+ none
276+ )
277+ , Font.size size
278+ ]
279+ ++ labels
280+ )
281+ (text "Typography")
282+
283+
284+adjusted size adjustment =
285+ column
286+ [ spacing 48
287+ , centerX
288+ , centerY
289+ ]
290+ [ el
291+ [ Font.size 32 ]
292+ (text "New Adjustments in Els")
293+ , row
294+ [ Font.size 85
295+ , padding 80
296+ , spacing 48
297+ ]
298+ [ el
299+ [ Font.size 95
300+ , Font.full
301+ , Background.color (rgb 0 0.8 0.9)
302+ , above (el [ Font.size 24, moveUp 6 ] (text "full height"))
303+ , onLeft <|
304+ el
305+ [ centerY
306+ , width (px 40)
307+ , height (px 95)
308+ , Background.color (rgb 0.9 0.8 0)
309+ ]
310+ none
311+ ]
312+ (text "Typography")
313+ , el
314+ [ Font.sizeByCapital
315+ , Font.size 85
316+ , Background.color (rgb 0 0.8 0.9)
317+ , above (el [ Font.size 24, moveUp 6 ] (text "corrected capital"))
318+ , onLeft <|
319+ el
320+ [ centerY
321+ , width (px 40)
322+ , height (px 85)
323+ , Background.color (rgb 0.9 0.8 0)
324+ ]
325+ none
326+ ]
327+ (text "Typography")
328+ ]
329+ , el [ Font.size 32 ] (text "Standard Defaults in CSS")
330+ , row
331+ [ spacing 32
332+ , Font.size 120
333+ ]
334+ [ el
335+ [ Background.color (rgb 0 0.8 0.9)
336+ , style "line-height" "normal"
337+ , class "lh-norm"
338+ , above (el [ Font.size 12 ] (text "line-height: normal"))
339+ ]
340+ (text "Typography")
341+ , el
342+ [ Background.color (rgb 0 0.8 0.9)
343+ , style "line-height" "1"
344+ , above (el [ Font.size 12 ] (text "line-height: 1"))
345+ ]
346+ (text "Typography")
347+ ]
348+ , row [ spacing 120 ]
349+ [ paragraph
350+ [ Font.size 25
351+ , spacing 5
352+ , width (px 200)
353+ , Background.color
354+ (rgb 0 0.8 0.9)
355+ , above (el [ Font.size 32, moveUp 32 ] (text "Normal Paragraphs"))
356+ ]
357+ [ el [ Font.size 55, alignLeft, Background.color (rgb 0.9 0.8 0) ] (text "L")
358+ , text "orem Ipsum is simply dummy text of the printing and typesetting industry."
359+ ]
360+ , paragraph
361+ [ Font.size 45
362+ , spacing 10
363+ , width (px 600)
364+ , inFront
365+ (el
366+ [ width (px 100)
367+ , height (px 5)
368+ , moveDown 45
369+ , alignRight
370+ , Background.color (rgba 0.9 0.8 0.2 0.5)
371+ ]
372+ none
373+ )
374+ , inFront
375+ (el
376+ [ width (px 100)
377+ , height (px 45)
378+ , alignRight
379+ , Background.color (rgba 0 0 0 0.5)
380+ ]
381+ none
382+ )
383+ , Background.color
384+ (rgb 0 0.8 0.9)
385+ , above
386+ (el [ Font.size 32, moveUp 32 ] (text "Corrected Paragraphs"))
387+ ]
388+ [ el
389+ [ Font.size 100
390+ , alignLeft
391+ , Background.color (rgb 0.9 0.8 0)
392+ , Font.sizeByCapital
393+ ]
394+ (text "C")
395+ , text "ontrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32."
396+ ]
397+ ]
398+ ]
399+
400+
401+corrected converted label =
402+ el
403+ [ Background.color (rgb 0 0.8 0.9)
404+ , style "display" "block"
405+ , above (el [ Font.size 12, moveUp 6 ] (text label))
406+ , style "line-height" (String.fromFloat converted.height)
407+ , below
408+ (column [ Font.size 12, spacing 5, moveDown 10 ]
409+ [ text ("height: " ++ String.left 5 (String.fromFloat converted.height))
410+ , text ("vertical: " ++ String.left 5 (String.fromFloat converted.vertical))
411+ ]
412+ )
413+ ]
414+ (el
415+ [ style "display" "inline-block"
416+ , style "line-height" (String.fromFloat converted.height)
417+ , style "vertical-align" (String.fromFloat converted.vertical ++ "em")
418+ ]
419+ (text "Typography")
420+ )
421+
422+
423+convertAdjustment adjustment =
424+ let
425+ base =
426+ adjustment.lineHeight
427+
428+ normalDescender =
429+ (adjustment.lineHeight - 1)
430+ / 2
431+
432+ oldMiddle =
433+ adjustment.lineHeight / 2
434+
435+ newCapitalMiddle =
436+ ((ascender - newBaseline) / 2) + newBaseline
437+
438+ newFullMiddle =
439+ ((ascender - descender) / 2) + descender
440+
441+ lines =
442+ [ adjustment.capital
443+ , adjustment.baseline
444+ , adjustment.descender
445+ , adjustment.lowercase
446+ ]
447+
448+ ascender =
449+ Maybe.withDefault adjustment.capital (List.maximum lines)
450+
451+ descender =
452+ Maybe.withDefault adjustment.descender (List.minimum lines)
453+
454+ newBaseline =
455+ lines
456+ |> List.filter (\x -> x /= descender)
457+ |> List.minimum
458+ |> Maybe.withDefault adjustment.baseline
459+
460+ capitalVertical =
461+ (oldMiddle - newCapitalMiddle) * 2
462+
463+ fullVertical =
464+ (oldMiddle - newFullMiddle) * 2
465+ in
466+ { full =
467+ { vertical = fullVertical
468+ , height =
469+ (ascender - descender)
470+ - abs fullVertical
471+ }
472+ , capital =
473+ { vertical = capitalVertical
474+ , height = (ascender - newBaseline) - abs capitalVertical
475+ }
476+ }
477+
478+
479+viewAdjustment label adjustment size left lineHeight updateWith =
480+ let
481+ fullHeight =
482+ toFloat size * 1.5
483+ in
484+ onLeft
485+ (el
486+ [ moveLeft left
487+ , height (px (round (toFloat size * lineHeight)))
488+ ]
489+ <|
490+ Input.slider
491+ [ Font.size 24
492+ , Element.behindContent
493+ (Element.el
494+ [ Element.width (Element.px 1)
495+ , Element.height Element.fill
496+ , Element.centerY
497+ , Background.color charcoal
498+ , Border.rounded 2
499+ ]
500+ Element.none
501+ )
502+ , height (px (round fullHeight))
503+ , width (px 1)
504+ , spacing 0
505+ , Background.color charcoal
506+ , below (el [ centerX ] (text (String.fromFloat adjustment)))
507+ , onRight
508+ (el
509+ [ height (px 0)
510+ , width (px 800)
511+ , moveRight 10
512+ , alignBottom
513+ , moveUp (fullHeight * (adjustment / lineHeight))
514+ , Border.color (rgb 0 0 0)
515+ , Border.dashed
516+ , Border.widthEach
517+ { top = 1
518+ , right = 0
519+ , bottom = 0
520+ , left = 0
521+ }
522+ ]
523+ none
524+ )
525+ ]
526+ { label = Input.labelHidden "font adjustment"
527+ , max = lineHeight
528+ , min = 0
529+ , onChange =
530+ \x ->
531+ UpdateAdjustment
532+ (updateWith x)
533+ , step = Just 0.005
534+ , thumb =
535+ Input.thumb
536+ [ Element.width (Element.px 16)
537+ , Element.height (Element.px 16)
538+ , Border.rounded 8
539+ , Border.width 1
540+ , Border.color (Element.rgb 0.5 0.5 0.5)
541+ , Background.color (Element.rgb 1 1 1)
542+ ]
543+ , value = adjustment
544+ }
545+ )
deps/elm-ui/experiments/font-adjustment-updated/elm.jsonnew file+25
@@ -0,0 +1,25 @@
1+{
2+ "type": "application",
3+ "source-directories": [
4+ ".",
5+ "../../src/"
6+ ],
7+ "elm-version": "0.19.0",
8+ "dependencies": {
9+ "direct": {
10+ "elm/browser": "1.0.0",
11+ "elm/core": "1.0.0",
12+ "elm/html": "1.0.0",
13+ "elm/json": "1.0.0",
14+ "elm/virtual-dom": "1.0.0"
15+ },
16+ "indirect": {
17+ "elm/time": "1.0.0",
18+ "elm/url": "1.0.0"
19+ }
20+ },
21+ "test-dependencies": {
22+ "direct": {},
23+ "indirect": {}
24+ }
25+}
deps/elm-ui/experiments/font-adjustment/FontAdjustment.elmnew file+365
@@ -0,0 +1,365 @@
1+module Main exposing (main)
2+
3+{-| Line Height as its specified through CSS doesn't make a whole lot of sense typographically.
4+
5+We also run into issues with sizing a font. The font size generally refers to the full type size (from the top of ascendors to the bottom of descenders)
6+
7+However, sometimes we might want to size things from the top of the Capital to the baseline.
8+
9+Or from the top of the x-height to the baseline.
10+
11+The main place this shows up is for dropped capitals, and for text on buttons.
12+
13+-}
14+
15+import Browser
16+import Element exposing (..)
17+import Element.Background as Background
18+import Element.Border as Border
19+import Element.Font as Font
20+import Element.Input as Input
21+import Element.Lazy
22+import Html.Attributes
23+
24+
25+type alias FontAdjustment =
26+ { lineHeight : Float
27+ , capital : Line
28+ , lowercase : Line
29+ , baseline : Line
30+ , descender : Line
31+ }
32+
33+
34+type alias Line =
35+ Float
36+
37+
38+type Msg
39+ = UpdateAdjustment FontAdjustment
40+
41+
42+edges =
43+ { top = 0
44+ , right = 0
45+ , bottom = 0
46+ , left = 0
47+ }
48+
49+
50+default =
51+ { capital = 1.15
52+ , lowercase = 0.96
53+ , baseline = 0.465
54+ , descender = 0.245
55+ , lineHeight = 1.5
56+ }
57+
58+
59+init =
60+ { adjustment =
61+ default
62+ , converted =
63+ convertAdjustment default
64+ }
65+
66+
67+update msg model =
68+ case msg of
69+ UpdateAdjustment adj ->
70+ { model
71+ | adjustment = adj
72+ , converted = convertAdjustment adj
73+ }
74+
75+
76+main =
77+ Browser.sandbox
78+ { init = init
79+ , update = update
80+ , view = view
81+ }
82+
83+
84+view model =
85+ Element.layout
86+ [ Background.color (rgba 1 1 1 1)
87+ , Font.color (rgba 0 0 0 1)
88+ , Font.family
89+ [ -- Font.external
90+ -- { url = "https://fonts.googleapis.com/css?family=EB+Garamond"
91+ -- , name = "EB Garamond"
92+ -- }
93+ Font.external
94+ { url = "https://fonts.googleapis.com/css?family=Catamaran"
95+ , name = "Catamaran"
96+ }
97+ , Font.sansSerif
98+ ]
99+ ]
100+ <|
101+ column [ width fill, height fill, spacing 128 ]
102+ [ adjustor 120 model.adjustment
103+ , adjusted 120 model.converted
104+ ]
105+
106+
107+style name val =
108+ htmlAttribute (Html.Attributes.style name val)
109+
110+
111+fontSize pixels lineHeight up =
112+ [ Font.size pixels
113+
114+ -- , htmlAttribute (Html.Attributes.style "line-height" lineHeight)
115+ -- , Background.color (rgb 0 0.8 0.9)
116+ -- , onLeft
117+ -- (el
118+ -- [ Background.color (rgb 0 0 0)
119+ -- , width (px 20)
120+ -- , height (px pixels)
121+ -- , moveUp up
122+ -- ]
123+ -- none
124+ -- )
125+ ]
126+
127+
128+charcoal =
129+ rgb 0.7 0.7 0.7
130+
131+
132+adjustor size adjustment =
133+ let
134+ labels =
135+ [ viewAdjustment "Type Height" adjustment.capital size 180 adjustment.lineHeight (\capital -> { adjustment | capital = capital })
136+ , viewAdjustment "Lowercase Height" adjustment.lowercase size 60 adjustment.lineHeight (\lowercase -> { adjustment | lowercase = lowercase })
137+ , viewAdjustment "Baseline" adjustment.baseline size 120 adjustment.lineHeight (\baseline -> { adjustment | baseline = baseline })
138+ , viewAdjustment "Descender" adjustment.descender size 0 adjustment.lineHeight (\descender -> { adjustment | descender = descender })
139+ ]
140+ in
141+ el
142+ ([ centerX
143+ , centerY
144+ , Background.color (rgb 0 0.8 0.9)
145+ , style "line-height" (String.fromFloat adjustment.lineHeight)
146+ , onRight
147+ (el
148+ [ centerY
149+ , width (px 40)
150+
151+ -- , height (px (round (toFloat size * (1 / 1.5))))
152+ , height (px size)
153+ , Background.color (rgb 0.9 0.8 0)
154+ ]
155+ none
156+ )
157+ , Font.size size
158+ ]
159+ ++ labels
160+ )
161+ (text "Typography")
162+
163+
164+adjusted size adjustment =
165+ column
166+ [ spacing 48
167+ , centerX
168+ , centerY
169+ ]
170+ [ row
171+ [ spacing 32
172+ , Font.size 120
173+ , above (text "hi")
174+ ]
175+ [ el
176+ [ Background.color (rgb 0 0.8 0.9)
177+ , style "line-height" "normal"
178+ , above (el [ Font.size 12 ] (text "line-height: normal"))
179+ ]
180+ (text "Typography")
181+ , el
182+ [ Background.color (rgb 0 0.8 0.9)
183+ , style "line-height" "1"
184+ , above (el [ Font.size 12 ] (text "line-height: 1"))
185+ ]
186+ (text "Typography")
187+ ]
188+ , row
189+ [ spacing 32
190+ , Font.size 120
191+ ]
192+ [ corrected adjustment.full "corrected"
193+ , corrected adjustment.capital "corrected capital"
194+ ]
195+ , paragraph [ Font.size 25, spacing 5, width (px 200) ]
196+ [ el [ Font.size 55, alignLeft ] (text "L")
197+ , text "orem Ipsum is simply dummy text of the printing and typesetting industry."
198+ ]
199+ ]
200+
201+
202+corrected converted label =
203+ el
204+ [ Background.color (rgb 0 0.8 0.9)
205+ , style "display" "block"
206+ , above (el [ Font.size 12, moveUp 6 ] (text label))
207+ , style "line-height" (String.fromFloat converted.height)
208+ , below
209+ (column [ Font.size 12, spacing 5, moveDown 10 ]
210+ [ text ("height: " ++ String.left 5 (String.fromFloat converted.height))
211+ , text ("vertical: " ++ String.left 5 (String.fromFloat converted.vertical))
212+ ]
213+ )
214+ ]
215+ (el
216+ [ style "display" "inline-block"
217+ , style "line-height" (String.fromFloat converted.height)
218+ , style "vertical-align" (String.fromFloat converted.vertical ++ "em")
219+ ]
220+ (text "Typography")
221+ )
222+
223+
224+convertAdjustment adjustment =
225+ let
226+ base =
227+ adjustment.lineHeight
228+
229+ normalDescender =
230+ (adjustment.lineHeight - 1)
231+ / 2
232+
233+ oldMiddle =
234+ adjustment.lineHeight / 2
235+
236+ newCapitalMiddle =
237+ ((ascender - newBaseline) / 2) + newBaseline
238+
239+ newFullMiddle =
240+ ((ascender - descender) / 2) + descender
241+
242+ lines =
243+ [ adjustment.capital
244+ , adjustment.baseline
245+ , adjustment.descender
246+ , adjustment.lowercase
247+ ]
248+
249+ ascender =
250+ Maybe.withDefault adjustment.capital (List.maximum lines)
251+
252+ descender =
253+ Maybe.withDefault adjustment.descender (List.minimum lines)
254+
255+ newBaseline =
256+ lines
257+ |> List.filter (\x -> x /= descender)
258+ |> List.minimum
259+ |> Maybe.withDefault adjustment.baseline
260+
261+ capitalVertical =
262+ (oldMiddle - newCapitalMiddle) * 2
263+
264+ fullVertical =
265+ (oldMiddle - newFullMiddle) * 2
266+ in
267+ { full =
268+ { vertical = fullVertical
269+ , height =
270+ (ascender - descender)
271+ - abs fullVertical
272+ }
273+ , capital =
274+ { vertical = capitalVertical
275+ , height = (ascender - newBaseline) - abs capitalVertical
276+ }
277+ }
278+
279+
280+viewAdjustment label adjustment size left lineHeight updateWith =
281+ let
282+ fullHeight =
283+ toFloat size * 1.5
284+ in
285+ onLeft
286+ (el
287+ [ moveLeft left
288+
289+ -- , moveUp (0.125 * toFloat size)
290+ , height (px (round (toFloat size * lineHeight)))
291+ ]
292+ <|
293+ Input.slider
294+ [ Font.size 24
295+ , Element.behindContent
296+ (Element.el
297+ [ Element.width (Element.px 1)
298+ , Element.height Element.fill
299+ , Element.centerY
300+ , Background.color charcoal
301+ , Border.rounded 2
302+ ]
303+ Element.none
304+ )
305+ , height (px (round fullHeight))
306+ , width (px 1)
307+ , spacing 0
308+ , Background.color charcoal
309+ , below (el [ centerX ] (text (String.fromFloat adjustment)))
310+ , onRight
311+ (el
312+ [ height (px 0)
313+ , width (px 800)
314+ , moveRight 10
315+ , alignBottom
316+ , moveUp (fullHeight * (adjustment / lineHeight))
317+ , Border.color (rgb 0 0 0)
318+ , Border.dashed
319+ , Border.widthEach
320+ { top = 1
321+ , right = 0
322+ , bottom = 0
323+ , left = 0
324+ }
325+ ]
326+ none
327+ )
328+ ]
329+ { label = Input.labelAbove [ Font.size 18 ] (text "")
330+ , max = lineHeight
331+ , min = 0
332+ , onChange =
333+ \x ->
334+ UpdateAdjustment
335+ (updateWith x)
336+ , step = Just 0.005
337+ , thumb =
338+ Input.thumb
339+ [ Element.width (Element.px 16)
340+ , Element.height (Element.px 16)
341+ , Border.rounded 8
342+ , Border.width 1
343+ , Border.color (Element.rgb 0.5 0.5 0.5)
344+ , Background.color (Element.rgb 1 1 1)
345+
346+ -- , onRight
347+ -- (el
348+ -- [ height (px 0)
349+ -- , width (px 1200)
350+ -- , moveDown 8
351+ -- , Border.color (rgb 0 0 0)
352+ -- , Border.dashed
353+ -- , Border.widthEach
354+ -- { top = 1
355+ -- , right = 0
356+ -- , bottom = 0
357+ -- , left = 0
358+ -- }
359+ -- ]
360+ -- none
361+ -- )
362+ ]
363+ , value = adjustment
364+ }
365+ )
deps/elm-ui/experiments/font-adjustment/elm.jsonnew file+25
@@ -0,0 +1,25 @@
1+{
2+ "type": "application",
3+ "source-directories": [
4+ ".",
5+ "../../src/"
6+ ],
7+ "elm-version": "0.19.0",
8+ "dependencies": {
9+ "direct": {
10+ "elm/browser": "1.0.0",
11+ "elm/core": "1.0.0",
12+ "elm/html": "1.0.0",
13+ "elm/json": "1.0.0",
14+ "elm/virtual-dom": "1.0.0"
15+ },
16+ "indirect": {
17+ "elm/time": "1.0.0",
18+ "elm/url": "1.0.0"
19+ }
20+ },
21+ "test-dependencies": {
22+ "direct": {},
23+ "indirect": {}
24+ }
25+}
deps/elm-ui/experiments/masks/Test.elmnew file+10
@@ -0,0 +1,10 @@
1+module Main exposing (..)
2+
3+{-| -}
4+
5+import Html
6+import MaskedInput
7+
8+
9+main =
10+ Html.text "Testing"
deps/elm-ui/experiments/masks/elm.jsonnew file+27
@@ -0,0 +1,27 @@
1+{
2+ "type": "application",
3+ "source-directories": [
4+ ".",
5+ "src"
6+ ],
7+ "elm-version": "0.19.0",
8+ "dependencies": {
9+ "direct": {
10+ "elm/browser": "1.0.0",
11+ "elm/core": "1.0.0",
12+ "elm/html": "1.0.0",
13+ "elm/json": "1.0.0",
14+ "elm/parser": "1.0.0",
15+ "elm/virtual-dom": "1.0.0",
16+ "elm-community/list-extra": "8.0.0"
17+ },
18+ "indirect": {
19+ "elm/time": "1.0.0",
20+ "elm/url": "1.0.0"
21+ }
22+ },
23+ "test-dependencies": {
24+ "direct": {},
25+ "indirect": {}
26+ }
27+}
deps/elm-ui/experiments/masks/src/MaskedInput.elmnew file+130
@@ -0,0 +1,130 @@
1+module MaskedInput exposing (..)
2+
3+{-| When we've created a Mask, it should be able to:
4+
5+ - The validator's job is only to say if an entire string is valid.
6+ - If a string is valid, then a message is sent out with the updated value.
7+ - If a string is not valid, then the last(i.e. the current) value is sent out on a message.
8+ - We have to send out a message on every input or else we'll get out of sync.(?)
9+
10+ - The formatter's job is to take an input string and to format it into a view-string
11+
12+ - The capturing parser's job is to transform the input string into the desired value.
13+ - If the parser fails, we keep returning `Partial`
14+ - As soon as it succeeds, we can return `Full`, which can have a value extracted.
15+
16+First pass at full description.
17+
18+Mask is defined in a view.
19+
20+ - An initial string is potentially given.
21+ - String is formatted and displayed
22+ - onInput handler is registered which parses the value, and creates either a Partial or a Full
23+ - The onInput handler will return the formatted string.
24+ ->? we could diff it against a previous formatted string to see what changed. Maybe too complicated
25+ ->? Capture keyboard events directly and make modifications there. What about pasting?
26+ ->! Have the parser operate directly on the formatted string.
27+
28+-}
29+
30+import Parser exposing (Parser)
31+
32+
33+type Masked input
34+ = Mask
35+ { capture : Parser input -- String -> input
36+ , format : List Formatter -- tel: "86" -> "(86 ) - "
37+ , validate : List Validator -- Is a character allowed to be typed
38+ }
39+
40+
41+type Validator
42+ = Validator Int (Char -> Bool)
43+
44+
45+type Formatter
46+ = Exactly String
47+ | FromInput Int (Maybe Hint) -- hint is shown if no string can be retrieved
48+
49+
50+type alias Hint =
51+ String
52+
53+
54+type Captured thing
55+ = Partial String
56+ | Full thing String
57+
58+
59+capture : input -> Masked input
60+capture value =
61+ Mask
62+ { capture = Parser.succeed value
63+ , format = []
64+ , validate = []
65+ }
66+
67+
68+{-| Shows a static string.
69+-}
70+show str (Mask mask) =
71+ Mask
72+ { mask
73+ | format = mask.format ++ [ Exactly str ]
74+ , capture = Parser.token str
75+ }
76+
77+
78+type alias Match =
79+ { length : Int
80+ , valid : Char -> Bool
81+ , hint : Maybe String
82+ }
83+
84+
85+{-| -}
86+match matcher (Mask mask) =
87+ Mask
88+ { mask
89+ | format = mask.format ++ [ FromInput matcher.length matcher.hint ]
90+ , validate = mask.validate ++ [ Validator matcher.length matcher.valid ]
91+ , capture = Parser.exactly matcher.length matcher.valid
92+ }
93+
94+
95+
96+-- map : (a -> b) -> Masked a -> Masked b
97+-- map =
98+-- Debug.crash "TODO"
99+-- map2 :
100+-- (a -> b -> value)
101+-- -> Masked a
102+-- -> Masked b
103+-- -> Masked value
104+-- map2 =
105+-- Debug.crash "TODO"
106+
107+
108+view : String -> Masked input -> Element msg
109+view =
110+ Debug.crash
111+
112+
113+captureValue : String -> Masked input -> Captured input
114+captureValue input (Mask mask) =
115+ case Parser.run mask.capture input of
116+ Ok val ->
117+ Full val input
118+
119+ Err _ ->
120+ Partial input
121+
122+
123+valid : Captured input -> Maybe input
124+valid cap =
125+ case cap of
126+ Partial _ ->
127+ Nothing
128+
129+ Full result _ ->
130+ Just result
deps/elm-ui/experiments/masks/src/Notes.elmnew file+189
@@ -0,0 +1,189 @@
1+module Element.Input.Mask exposing (..)
2+
3+{-| With masked input we can simultaneously descibe:
4+
5+ - a parser to only allow specific arguments
6+ - We have a set of expected characters and how many of them to expect.
7+ - Static formating. Meaning show a `/` between two numbers, but it's not part of the input
8+ - Hints. These are mini placeholder values for a section of your input.
9+ - Autocomplete suggestions. These are suggestions that can be selected and completed with `tab`.
10+
11+-}
12+
13+
14+type Masked input
15+ = Mask (List Pattern)
16+
17+
18+type Pattern
19+ = Capture Limit (Char -> Bool)
20+ | Decimal
21+ | Decoration String
22+
23+
24+type Limit
25+ = NoLimit
26+ | Min Int
27+ | Max Int
28+ | MinMax Int Int
29+
30+
31+type Input thing
32+ = Partial String
33+ | Full thing String
34+
35+
36+type alias CreditCard =
37+ { number : String
38+ , expMonth : String
39+ , expYear : String
40+ , ccv : String
41+ }
42+
43+
44+type alias CreditCardNumber =
45+ String
46+
47+
48+example =
49+ capture (\one two three four -> CreditCardNumber (one ++ two ++ three ++ four))
50+ |> Mask.stringWith
51+ { length = 4
52+ , valid = String.isDigit
53+ , hint = "1234"
54+ }
55+ |> Mask.show " "
56+ |> Mask.stringWith
57+ { length = 4
58+ , valid = String.isDigit
59+ , hint = "1234"
60+ }
61+ |> Mask.show " "
62+ |> Mask.stringWith
63+ { length = 4
64+ , valid = String.isDigit
65+ , hint = "1234"
66+ }
67+ |> Mask.space
68+ |> Mask.stringWith
69+ { length = 4
70+ , valid = String.isDigit
71+ , hint = "1234"
72+ }
73+ |> Mask.andThen
74+ (\creditcard ->
75+ capture (CreditCard creditNumber)
76+ |> Mask.show "1234"
77+ -- last four digits of credit card
78+ |> Mask.space
79+ |> Mask.stringWith
80+ { length = 2
81+ , valid = String.isDigit
82+ , hint = "MM"
83+ }
84+ |> Mask.show "/"
85+ |> Mask.stringWith
86+ { length = 2
87+ , valid = String.isDigit
88+ , hint = "YY"
89+ }
90+ |> Mask.space
91+ |> Mask.stringWith
92+ { length = 4
93+ , valid = String.isDigit
94+ , hint = "CCV"
95+ }
96+ )
97+
98+
99+float =
100+ Mask.int
101+ |> Mask.token "."
102+ |> Mask.andThen
103+ (\one ->
104+ masked (\two -> one + two)
105+ --combine ints in a way
106+ |> Mask.token (toString one)
107+ |> Mask.token "."
108+ |> Mask.stringWith
109+ { length = 3 -- No length restrictions
110+ , valid = String.isDigit
111+ , hint = "CCV"
112+ }
113+ )
114+
115+
116+{-| <https://ellie-app.com/JJxYGFKptVa1>
117+
118+<https://ellie-app.com/JKMJgSTtn2a1>
119+
120+<https://ellie-app.com/KdY8X99fqba1>
121+
122+-}
123+
124+
125+
126+-- type Masked input
127+-- = Mask
128+-- { capture : Parser input -- String -> input
129+-- , format : List Formatter -- tel: "86" -> "(86 ) - "
130+-- , validate : List Validator -- Is a character allowed to be typed
131+-- }
132+-- type Validator
133+-- = Match Int (Char -> Bool)
134+-- type Formatter
135+-- = Exactly String
136+-- | FromInput Int Hint -- hint is shown if no string can be retrieved
137+-- type alias Hint =
138+-- String
139+-- -- type Masked input =
140+-- -- { parser : Parser input
141+-- -- ,
142+-- -- }
143+-- {-| We want this to be in
144+-- ---> formatting
145+-- -x-> result
146+-- -}
147+-- show str mask =
148+-- mask
149+-- {-| ---> formatting
150+-- ---> result
151+-- | if nothing's parsed
152+-- hint ---> formatting
153+-- hint -x-> result
154+-- -}
155+-- stringWith options mask =
156+-- mask
157+-- type Pattern input
158+-- = Capture Limit (Char -> Bool)
159+-- | Decimal
160+-- | Show String
161+-- type Limit
162+-- = NoLimit
163+-- | Min Int
164+-- | Max Int
165+-- | MinMax Int Int
166+-- type Captured input
167+-- = Partial String
168+-- | Full input String
169+-- {-| A placeholder ot represent different pieces having different styles
170+-- -}
171+-- type Styled
172+-- = Styled String String
173+-- render : String -> Masked input -> List Styled
174+-- captureValue : String -> Masked input -> Captured input
175+-- capture : input -> Masked input
176+-- map : (a -> b) -> Masked a -> Masked b
177+-- map2 :
178+-- (a -> b -> value)
179+-- -> Masked a
180+-- -> Masked b
181+-- -> Masked value
182+-- andThen : (a -> Masked b) -> Masked a -> Masked b
183+-- valid : Captured input -> Maybe input
184+-- valid cap =
185+-- case cap of
186+-- Partial _ ->
187+-- Nothing
188+-- Full result _ ->
189+-- Just result
deps/elm-ui/experiments/palette/PaletteTest.elmnew file+37
@@ -0,0 +1,37 @@
1+module Main exposing (..)
2+
3+import Element exposing (..)
4+import Html
5+import Palette
6+
7+
8+{- First, Define our Palette
9+
10+ Usually this would be in a different file.
11+
12+-}
13+
14+
15+type alias MyColorPalette =
16+ { primary : Palette.Protected Color
17+ , secondary : Palette.Protected Color
18+ }
19+
20+myColors : Palette.Colors MyColorPalette
21+myColors =
22+ Palette.colors MyColorPalette
23+ |> Palette.color (rgb 1 0 0)
24+ |> Palette.color (rgb 1 0 1)
25+
26+main =
27+ Palette.layout myColors
28+ []
29+ (Palette.Element
30+ [
31+ -- Palette.bgColor red
32+ --
33+ Palette.bgColor .primary
34+ -- Palette.bgColor (Palette.dynamic (rgb 0 1 0))
35+ ]
36+ []
37+ )
deps/elm-ui/experiments/palette/elm.jsonnew file+27
@@ -0,0 +1,27 @@
1+{
2+ "type": "application",
3+ "source-directories": [
4+ ".",
5+ "src",
6+ "../src/"
7+ ],
8+ "elm-version": "0.19.0",
9+ "dependencies": {
10+ "direct": {
11+ "elm/browser": "1.0.0",
12+ "elm/core": "1.0.0",
13+ "elm/html": "1.0.0",
14+ "elm/json": "1.0.0",
15+ "elm/virtual-dom": "1.0.0",
16+ "elm-community/list-extra": "8.0.0"
17+ },
18+ "indirect": {
19+ "elm/time": "1.0.0",
20+ "elm/url": "1.0.0"
21+ }
22+ },
23+ "test-dependencies": {
24+ "direct": {},
25+ "indirect": {}
26+ }
27+}
deps/elm-ui/experiments/palette/src/Palette.elmnew file+214
@@ -0,0 +1,214 @@
1+module Palette exposing (..)
2+
3+{-| With palettes, we want the dev to be able to
4+
5+ - specify some colors
6+ - those colors then need to be rendered by the layout
7+ - those colors can then be referred to by name in the layout
8+ - A lookup is done to retrieve the classname
9+
10+-}
11+
12+import Element exposing (Color)
13+import Html exposing (Html)
14+import Html.Attributes
15+import Internal.Model as Internal
16+
17+
18+{- Declare a Palette of Colors (or any value, but colors for not) -}
19+{- -}
20+
21+
22+layout : Colors colors -> List (Attribute colors msg) -> Element colors msg -> Html msg
23+layout colorPalette attrs child =
24+ -- Render a "stylesheet"
25+ let
26+ ( html, dynamicStyles ) =
27+ renderPaletteElement colorPalette (Element attrs [ child ])
28+ in
29+ Html.div [ Html.Attributes.class "root" ]
30+ [ Html.text "static stylesheet"
31+ , Html.div
32+ [ Html.Attributes.style "padding" "20px"
33+ , Html.Attributes.style "whitespace" "pre"
34+ , Html.Attributes.style "border-radius" "4px"
35+ , Html.Attributes.style "background-color" "#CCDDCC"
36+ , Html.Attributes.style "font-family" "Open Sans"
37+ ]
38+ [ Html.text (String.join "\n" (renderColorPalette colorPalette)) ]
39+ , Html.node "style"
40+ []
41+ [ Html.text ("html,body,.root {width: 100%; height: 100%;}.ui {min-width:100px; min-height: 100px;}" ++ String.join "\n" (renderColorPalette colorPalette))
42+ ]
43+ , Html.text "dynamic stylesheet"
44+ , Html.div
45+ [ Html.Attributes.style "padding" "20px"
46+ , Html.Attributes.style "whitespace" "pre"
47+ , Html.Attributes.style "border-radius" "4px"
48+ , Html.Attributes.style "background-color" "#FFDDCC"
49+ , Html.Attributes.style "font-family" "Open Sans"
50+ ]
51+ [ Html.text (String.join "\n" dynamicStyles) ]
52+ , Html.node "style" [] [ Html.text (String.join "\n" dynamicStyles) ]
53+ , Html.text "content:"
54+ , html
55+ ]
56+
57+
58+renderColor clr =
59+ Internal.formatColor clr
60+
61+
62+colorRule clr =
63+ ".bg-clr-"
64+ ++ Internal.formatColorClass clr
65+ ++ "{ background-color:"
66+ ++ Internal.formatColor clr
67+ ++ " }"
68+
69+
70+renderColorPalette : Colors colors -> List String
71+renderColorPalette (Colors palette) =
72+ List.map
73+ colorRule
74+ palette.values
75+
76+
77+renderPaletteElement : Colors colors -> InternalElement (colors -> Protected Color) msg -> ( Html msg, List String )
78+renderPaletteElement colorPalette (Element attrs children) =
79+ let
80+ gatherAttr attr ( attributes, myAttrStyles ) =
81+ let
82+ ( cls, style ) =
83+ renderPaletteAttribute colorPalette attr
84+ in
85+ ( cls ++ " " ++ attributes, style :: myAttrStyles )
86+
87+ ( classes, attrStyles ) =
88+ List.foldl gatherAttr ( "", [] ) attrs
89+
90+ ( renderedChildren, styles ) =
91+ List.foldr gather ( [], attrStyles ) children
92+
93+ gather child ( rendered, existingStyles ) =
94+ let
95+ ( childHtml, childStyles ) =
96+ renderPaletteElement colorPalette child
97+ in
98+ ( childHtml :: rendered, childStyles ++ existingStyles )
99+ in
100+ ( Html.div [ Html.Attributes.class ("ui " ++ classes) ]
101+ renderedChildren
102+ , styles
103+ )
104+
105+
106+renderPaletteAttribute : Colors colors -> InternalAttribute (colors -> Protected Color) msg -> ( String, String )
107+renderPaletteAttribute (Colors palette) attribute =
108+ case attribute of
109+ InternalAttribute ->
110+ ( "ui", "" )
111+
112+ ColorStyle colorLookup ->
113+ case colorLookup palette.protected of
114+ Dynamic clr ->
115+ ( "bg-clr-" ++ Internal.formatColorClass clr, colorRule clr )
116+
117+ Protected clr ->
118+ ( "bg-clr-" ++ Internal.formatColorClass clr, "" )
119+
120+
121+renderAttribute : Colors color -> InternalAttribute Color msg -> String
122+renderAttribute (Colors palette) attribute =
123+ case attribute of
124+ InternalAttribute ->
125+ ""
126+
127+ ColorStyle clr ->
128+ "dynamic clr"
129+
130+
131+bgColor : color -> InternalAttribute color msg
132+bgColor clr =
133+ ColorStyle clr
134+
135+
136+{-| Concrete Values
137+-}
138+type alias Attr msg =
139+ InternalAttribute Color msg
140+
141+
142+{-| Palette based attributes
143+-}
144+type alias Attribute colors msg =
145+ InternalAttribute (colors -> Protected Color) msg
146+
147+
148+type alias Element colors msg =
149+ InternalElement (colors -> Protected Color) msg
150+
151+
152+type alias El msg =
153+ InternalElement Color msg
154+
155+
156+type InternalAttribute color msg
157+ = InternalAttribute
158+ | ColorStyle color
159+
160+
161+type InternalElement color msg
162+ = Element (List (InternalAttribute color msg)) (List (InternalElement color msg))
163+
164+
165+{-| This is how we keep track of something that's already rendered, (Protected), or needs to be rendered
166+-}
167+type Protected thing
168+ = Protected thing
169+ | Dynamic thing
170+
171+
172+
173+-- dynamic : Color -> Colors colors -> Protected Color
174+
175+
176+dynamic value palette =
177+ Dynamic value
178+
179+
180+
181+{- COLORS -}
182+
183+
184+type Colors a
185+ = Colors
186+ { protected : a
187+ , values : List Color
188+ }
189+
190+
191+colors : a -> Colors a
192+colors a =
193+ Colors
194+ { protected = a
195+ , values = []
196+ }
197+
198+
199+color : Color -> Colors (Protected Color -> a) -> Colors a
200+color clr pal =
201+ let
202+ addColor p =
203+ { protected = p.protected (Protected clr)
204+ , values = clr :: p.values
205+ }
206+ in
207+ map addColor pal
208+
209+
210+map : ({ protected : a, values : List Color } -> { protected : a1, values : List Color }) -> Colors a -> Colors a1
211+map fn pal =
212+ case pal of
213+ Colors a ->
214+ Colors (fn a)
deps/elm-ui/experiments/virtual-css/Main.elmnew file+46
@@ -0,0 +1,46 @@
1+module Main exposing (main)
2+
3+import Browser
4+import Element exposing (..)
5+import Element.Background as Background
6+import Element.Events as Events
7+import Element.Font as Font
8+import Html
9+import Internal.Model as Internal
10+
11+
12+main =
13+ Browser.sandbox
14+ { init = 0
15+ , update = update
16+ , view = view
17+ }
18+
19+
20+update msg model =
21+ case msg of
22+ Click ->
23+ model + 1
24+
25+
26+type Msg
27+ = Click
28+
29+
30+view model =
31+ Element.layoutWith
32+ { options =
33+ [ Internal.RenderModeOption
34+ Internal.WithVirtualCss
35+ ]
36+ }
37+ [ Events.onClick Click ]
38+ (el
39+ [ padding 10
40+ , Background.color (rgb 0 0 0.8)
41+ , Font.color (rgb 1 1 1)
42+ , centerX
43+ , centerY
44+ ]
45+ (text ("hello!" ++ String.fromInt model))
46+ )
deps/elm-ui/experiments/virtual-css/Makefilenew file+1
@@ -0,0 +1 @@
1+elm-live Main.elm --open --start-page=test.html -- --output=elm.js
deps/elm-ui/experiments/virtual-css/cssom.jsnew file+47
@@ -0,0 +1,47 @@
1+(function () {
2+ var ruleCache = new Set()
3+
4+ function createStyleNode() {
5+ const node = document.createElement('style')
6+ // Without it, IE will have a broken source order specificity if we
7+ // insert rules after we insert the style tag.
8+ // It seems to kick-off the source order specificity algorithm.
9+ node.textContent = '\n'
10+ document.head.appendChild(node);
11+ return node
12+ }
13+
14+ var staticSheet = createStyleNode();
15+ var sheet = createStyleNode().sheet;
16+
17+ function sync_static(newStyleString) {
18+ staticSheet.textContent = newStyleString
19+ }
20+
21+ function sync(newStyles) {
22+ Object.keys(newStyles).forEach((key) => {
23+ if (!ruleCache.has(key)) {
24+ const newRule = newStyles[key]
25+ for (var i = 0; i < newRule.length; i++) {
26+ sheet.insertRule(newRule[i])
27+ }
28+ ruleCache.add(key)
29+ }
30+ });
31+ }
32+
33+ class CssRulesNode extends HTMLElement {
34+ set rules(rules) {
35+ sync(rules);
36+ }
37+ }
38+ customElements.define('elm-ui-rules', CssRulesNode);
39+
40+ class CssStaticRulesNode extends HTMLElement {
41+ set rules(rules) {
42+ sync_static(rules);
43+ }
44+ }
45+ customElements.define('elm-ui-static-rules', CssStaticRulesNode);
46+
47+}())
deps/elm-ui/experiments/virtual-css/elm.jsonnew file+25
@@ -0,0 +1,25 @@
1+{
2+ "type": "application",
3+ "source-directories": [
4+ ".",
5+ "../../src/"
6+ ],
7+ "elm-version": "0.19.0",
8+ "dependencies": {
9+ "direct": {
10+ "elm/browser": "1.0.0",
11+ "elm/core": "1.0.0",
12+ "elm/html": "1.0.0",
13+ "elm/json": "1.0.0",
14+ "elm/virtual-dom": "1.0.0"
15+ },
16+ "indirect": {
17+ "elm/time": "1.0.0",
18+ "elm/url": "1.0.0"
19+ }
20+ },
21+ "test-dependencies": {
22+ "direct": {},
23+ "indirect": {}
24+ }
25+}
deps/elm-ui/experiments/virtual-css/test.htmlnew file+18
@@ -0,0 +1,18 @@
1+<!DOCTYPE HTML>
2+<html>
3+<head>
4+ <meta charset="UTF-8">
5+ <title>Main</title>
6+ <script src="cssom.js"></script>
7+ <script src="elm.js"></script>
8+</head>
9+
10+<body>
11+ <div id="elm"></div>
12+ <script>
13+ var app = Elm.Main.init({
14+ node: document.getElementById('elm')
15+ });
16+ </script>
17+</body>
18+</html>
deps/elm-ui/experiments/workspace/Basic.elmnew file+233
@@ -0,0 +1,233 @@
1+module Main exposing (main)
2+
3+{-| -}
4+
5+import Element exposing (..)
6+import Element.Background as Background
7+import Element.Font as Font
8+
9+
10+box =
11+ el [ height (px 30), width (px 200), Background.color (rgb 0 0.8 0.9) ] none
12+
13+
14+main =
15+ Element.layout
16+ [ Background.color (rgba 1 1 1 1)
17+ , Font.color (rgba 1 1 1 1)
18+ , Font.size 64
19+ , Font.family
20+ [ Font.external
21+ { url = "https://fonts.googleapis.com/css?family=EB+Garamond"
22+ , name = "EB Garamond"
23+ }
24+ , Font.sansSerif
25+ ]
26+ ]
27+ <|
28+ column
29+ [ spacing 40
30+ , Background.color (rgb 1 1 1)
31+ , centerX
32+ , inFront
33+ (el
34+ [ Background.color (rgb 1 0 0)
35+ , width (px 20)
36+ , height (px 20)
37+ ]
38+ (text "in front of everything")
39+ )
40+ , behindContent
41+ (el
42+ [ Background.color (rgb 0.5 0.7 0)
43+ , Font.color (rgb 1 1 1)
44+ , moveDown 30
45+ ]
46+ (text "hi there")
47+ )
48+ ]
49+ [ el
50+ [ Background.color (rgba 0 0.9 0.8 1)
51+ , Font.color (rgb 0 0 0)
52+ , behindContent
53+ (el
54+ [ Background.color (rgb 0.9 0.9 0)
55+ , Font.color (rgb 1 1 1)
56+ ]
57+ (text "hi there")
58+ )
59+ , inFront
60+ (el [ Background.color (rgb 0.9 0.9 0.5) ] (text "in front of stuff, behind one"))
61+
62+ -- , Font.sizeByCapital
63+ -- , Font.variant Font.smallCaps
64+ -- , Font.variant Font.ligatures
65+ -- , Font.variant Font.diagonalFractions
66+ ]
67+ (text "Quality 1st Hello stylish friend! ofl 123456 1/3")
68+ , row
69+ [ Background.color (rgba 0 0.9 0.8 1)
70+ , Font.color (rgb 0 0 0)
71+ , spacing 87
72+ , behindContent
73+ (el [ Background.color (rgb 0.9 0.9 0), Font.color (rgb 1 1 1) ] (text "hi there"))
74+ , inFront
75+ (el [ Background.color (rgb 0.9 0.9 0.5) ] (text "yo"))
76+
77+ -- , Font.sizeByCapital
78+ -- , Font.variant Font.smallCaps
79+ -- , Font.variant Font.ligatures
80+ -- , Font.variant Font.diagonalFractions
81+ ]
82+ [ text "Quality 1st Hello stylish friend! ofl 123456 1/3"
83+ ]
84+ , el
85+ [ Background.color (rgb 0.1 0.1 0.1)
86+ , width (px 200)
87+ , height (px 200)
88+
89+ -- , below
90+ -- (el
91+ -- [ Background.color (rgb 1 0 0)
92+ -- , width (px 20)
93+ -- , height (px 20)
94+ -- , moveDown 30
95+ -- ]
96+ -- none
97+ -- )
98+ , below
99+ (el
100+ [ Background.color (rgb 0.1 0.1 0.6)
101+ , width (px 150)
102+ , height (px 150)
103+
104+ -- , alignBottom
105+ ]
106+ none
107+ )
108+ ]
109+ none
110+ , el
111+ [ Background.color (rgb 0.1 0.1 0.1)
112+ , width (px 200)
113+ , height (px 200)
114+ , above
115+ (el
116+ [ Background.color (rgb 1 0 0)
117+ , width (px 20)
118+ , height (px 20)
119+
120+ -- , moveUp 30
121+ ]
122+ none
123+ )
124+ , onRight
125+ (el
126+ [ Background.color (rgb 1 0 0)
127+ , width (px 20)
128+ , height fill
129+
130+ -- , moveUp 30
131+ ]
132+ none
133+ )
134+
135+ -- , inFront
136+ -- (el
137+ -- [ Background.color (rgb 0.1 0.1 0.6)
138+ -- , width (px 150)
139+ -- , height (px 150)
140+ -- ]
141+ -- none
142+ -- )
143+ -- , above
144+ -- (el
145+ -- [ Background.color (rgb 1 0 0)
146+ -- , width (px 20)
147+ -- , height (px 20)
148+ -- , moveUp 30
149+ -- ]
150+ -- none
151+ -- )
152+ ]
153+ none
154+ , el
155+ [ Background.color (rgb 0.1 0.1 0.1)
156+ , width (px 200)
157+ , height (px 200)
158+ , below
159+ (el
160+ [ Background.color (rgb 1 0 0)
161+ , width fill
162+ , height (px 20)
163+ ]
164+ none
165+ )
166+ , above
167+ (el
168+ [ Background.color (rgb 1 0 0)
169+ , width fill
170+ , height (px 20)
171+ ]
172+ none
173+ )
174+ , onLeft
175+ (el
176+ [ Background.color (rgb 1 0 0)
177+ , width (px 20)
178+ , height fill
179+ ]
180+ none
181+ )
182+ , onRight
183+ (el
184+ [ Background.color (rgb 1 0 0)
185+ , width (px 20)
186+ , height fill
187+ ]
188+ none
189+ )
190+ ]
191+ none
192+ , el
193+ [ Background.color (rgb 0.1 0.1 0.1)
194+ , width (px 200)
195+ , height (px 200)
196+ , inFront
197+ (el
198+ [ Background.color (rgb 1 0 0)
199+ , width fill
200+ , height fill
201+ ]
202+ none
203+ )
204+ ]
205+ none
206+ ]
207+
208+
209+
210+-- row
211+-- [ --width (px 420)
212+-- padding 0
213+-- , spacing 20
214+-- , Background.color (rgb 0.2 0.2 0.3)
215+-- ]
216+-- [ box
217+-- , box
218+-- , box
219+-- -- , box
220+-- -- , box
221+-- ]
222+-- wrappedRow
223+-- [ width (px 420)
224+-- , padding 10
225+-- , spacing 20
226+-- , Background.color (rgb 0.2 0.2 0.3)
227+-- ]
228+-- [ box
229+-- , box
230+-- , box
231+-- , box
232+-- , box
233+-- ]
deps/elm-ui/experiments/workspace/Form.elmnew file+234
@@ -0,0 +1,234 @@
1+module Main exposing (Form, Lunch(..), Msg(..), blue, darkBlue, grey, init, main, red, update, view, white)
2+
3+{-| -}
4+
5+import Browser
6+import Element exposing (..)
7+import Element.Background as Background
8+import Element.Border as Border
9+import Element.Font as Font
10+import Element.Input as Input
11+import Element.Region as Region
12+import Html.Attributes
13+
14+
15+white =
16+ Element.rgb 1 1 1
17+
18+
19+grey =
20+ Element.rgb 0.9 0.9 0.9
21+
22+
23+blue =
24+ Element.rgb 0 0 0.8
25+
26+
27+red =
28+ Element.rgb 0.8 0 0
29+
30+
31+darkBlue =
32+ Element.rgb 0 0 0.9
33+
34+
35+main =
36+ Browser.sandbox
37+ { init = init
38+ , view = view
39+ , update = update
40+ }
41+
42+
43+init =
44+ { username = ""
45+ , password = ""
46+ , agreeTOS = False
47+ , comment = "Extra hot sauce?\n\n\nYes pls"
48+ , lunch = Gyro
49+ , spiciness = 2
50+ }
51+
52+
53+type alias Form =
54+ { username : String
55+ , password : String
56+ , agreeTOS : Bool
57+ , comment : String
58+ , lunch : Lunch
59+ , spiciness : Float
60+ }
61+
62+
63+type Msg
64+ = Update Form
65+
66+
67+update msg model =
68+ case Debug.log "msg" msg of
69+ Update new ->
70+ new
71+
72+
73+id i =
74+ htmlAttribute (Html.Attributes.id i)
75+
76+
77+type Lunch
78+ = Burrito
79+ | Taco
80+ | Gyro
81+
82+
83+view model =
84+ Element.layout
85+ [ Font.size 20
86+ ]
87+ <|
88+ Element.column
89+ [ width (px 800)
90+ , height shrink
91+ , centerY
92+ , centerX
93+ , spacing 36
94+ , padding 10
95+ ]
96+ [ el
97+ [ Region.heading 1
98+ , alignLeft
99+ , Font.size 36
100+ ]
101+ (text "Welcome to the Stylish Elephants Lunch Emporium")
102+ , Input.radio
103+ [ spacing 12
104+ , alpha 0.5
105+ , id "radio-1"
106+ ]
107+ { selected = Just model.lunch
108+ , onChange = \new -> Update { model | lunch = new }
109+ , label =
110+ -- Input.labelHidden "Just a label"
111+ Input.labelAbove
112+ [ Font.size 14
113+ , paddingXY 0 12
114+ ]
115+ (text "What would you like for lunch?")
116+ , options =
117+ [ Input.option Gyro (text "Gyro")
118+ , Input.option Burrito (text "Burrito")
119+ , Input.option Taco (text "Taco")
120+ ]
121+ }
122+ , Input.text
123+ [ spacing 12
124+ , id "text-1"
125+ ]
126+ { text = model.username
127+ , placeholder =
128+ Just
129+ (Input.placeholder
130+ [ focused
131+ [ moveUp 30 ]
132+ ]
133+ (text "Placeholder Label")
134+ )
135+ , onChange = \new -> Update { model | username = new }
136+ , label =
137+ Input.labelHidden "Just a label"
138+
139+ -- Input.labelBelow
140+ -- [ Font.size 14
141+ -- , focused
142+ -- [ moveUp 30 ]
143+ -- ]
144+ -- (text "Username")
145+ }
146+ , Input.currentPassword [ spacing 12, width shrink ]
147+ { text = model.password
148+ , placeholder = Nothing
149+ , onChange = \new -> Update { model | password = new }
150+ , label = Input.labelAbove [ Font.size 14 ] (text "Password")
151+ , show = False
152+ }
153+ , Input.multiline
154+ [ height
155+ (shrink
156+ |> maximum 400
157+ )
158+ , spacing 12
159+ , id "multiline-1"
160+ ]
161+ { text = model.comment
162+ , placeholder = Just (Input.placeholder [] (text "Extra hot sauce?\n\n\nYes pls"))
163+ , onChange = \new -> Update { model | comment = new }
164+ , label =
165+ -- Input.labelAbove [ Font.size 14 ] (text "Leave a comment!")
166+ Input.labelHidden "Just a label"
167+ , spellcheck = False
168+ }
169+ , Input.checkbox [ id "checkbox-1" ]
170+ { checked = model.agreeTOS
171+ , onChange = \new -> Update { model | agreeTOS = new }
172+ , icon = Input.defaultCheckbox
173+ , label =
174+ -- Input.labelRight [] (text "Agree to Terms of Service")
175+ Input.labelHidden "Just a label"
176+ }
177+ , Input.slider
178+ [ Element.height (Element.px 30)
179+ , Element.behindContent
180+ (Element.el
181+ [ Element.width Element.fill
182+ , Element.height (Element.px 2)
183+ , Element.centerY
184+ , Background.color grey
185+ , Border.rounded 2
186+ ]
187+ Element.none
188+ )
189+ ]
190+ { onChange = \new -> Update { model | spiciness = new }
191+ , label = Input.labelAbove [] (text ("Spiciness: " ++ String.fromFloat model.spiciness))
192+ , min = 0
193+ , max = 3.2
194+ , step = Nothing
195+ , value = model.spiciness
196+ , thumb =
197+ Input.defaultThumb
198+ }
199+ , --el [height (px 300), width (px 30)] <|
200+ Input.slider
201+ [ Element.width (Element.px 40)
202+ , Element.height (Element.px 80)
203+ , Element.behindContent
204+ (Element.el
205+ [ Element.height Element.fill
206+ , Element.width (Element.px 2)
207+ , Element.centerX
208+ , Background.color grey
209+ , Border.rounded 2
210+ ]
211+ Element.none
212+ )
213+ ]
214+ { onChange = \new -> Update { model | spiciness = new }
215+ , label = Input.labelAbove [] (text ("Spiciness: " ++ String.fromFloat model.spiciness))
216+ , min = 0
217+ , max = 3.2
218+ , step = Nothing
219+ , value = model.spiciness
220+ , thumb =
221+ Input.defaultThumb
222+ }
223+ , Input.button
224+ [-- Background.color blue
225+ -- , Font.color white
226+ -- , Border.color darkBlue
227+ -- , paddingXY 32 16
228+ -- , Border.rounded 3
229+ -- , width fill
230+ ]
231+ { onPress = Nothing
232+ , label = Element.text "Place your lunch order!"
233+ }
234+ ]
deps/elm-ui/experiments/workspace/Scrollbars.elmnew file+204
@@ -0,0 +1,204 @@
1+module Main exposing (main)
2+
3+{-| -}
4+
5+import Element exposing (..)
6+import Element.Background as Background
7+import Element.Font as Font
8+
9+
10+box =
11+ el [ height (px 30), width (px 200), Background.color (rgb 0 0.8 0.9) ] none
12+
13+
14+main =
15+ Element.layout
16+ [ Background.color (rgba 1 1 1 1)
17+ , Font.color (rgba 1 1 1 1)
18+ , Font.size 64
19+
20+ -- , Font.italic
21+ , Font.family
22+ [ Font.external
23+ { url = "https://fonts.googleapis.com/css?family=EB+Garamond"
24+ , name = "EB Garamond"
25+ }
26+
27+ -- Font.with
28+ -- { url = Just "https://fonts.googleapis.com/css?family=EB+Garamond"
29+ -- , name = "EB Garamond"
30+ -- , adjustment =
31+ -- { capital = 1.09
32+ -- , lowercase = 0.81
33+ -- , baseline = 0.385
34+ -- , descender = 0.095
35+ -- }
36+ -- , variants =
37+ -- [ Font.swash 1
38+ -- , Font.smallCaps
39+ -- -- , Font.diagonalFractions
40+ -- -- , Font.ordinal
41+ -- -- , Font.ligatures
42+ -- ]
43+ -- }
44+ -- Font.with
45+ -- { url = Just "https://fonts.googleapis.com/css?family=Raleway"
46+ -- , name = "Raleway"
47+ -- , adjustment =
48+ -- { capital = 1.09
49+ -- , lowercase = 0.81
50+ -- , baseline = 0.385
51+ -- , descender = 0.095
52+ -- }
53+ -- , variants =
54+ -- [ Font.swash 2
55+ -- , Font.ordinal
56+ -- , Font.ligatures
57+ -- -- , Font.small
58+ -- ]
59+ -- }
60+ , Font.sansSerif
61+ ]
62+ ]
63+ <|
64+ column
65+ [ spacing 20
66+ , Background.color (rgb 1 1 1)
67+ , inFront
68+ (el
69+ [ Background.color (rgb 1 0 0)
70+ , width (px 20)
71+ , height (px 20)
72+ ]
73+ none
74+ )
75+ , behindContent
76+ (el
77+ [ Background.color (rgb 0.5 0.7 0)
78+ , Font.color (rgb 1 1 1)
79+ , moveDown 30
80+ ]
81+ (text "hi there")
82+ )
83+ ]
84+ [ el
85+ [ Background.color (rgba 0 0.9 0.8 1)
86+ , Font.color (rgb 0 0 0)
87+ , behindContent
88+ (el
89+ [ Background.color (rgb 0.9 0.9 0)
90+ , Font.color (rgb 1 1 1)
91+ ]
92+ (text "hi there")
93+ )
94+ , inFront
95+ (el [ Background.color (rgb 0.9 0.9 0.5) ] (text "yo"))
96+
97+ -- , Font.sizeByCapital
98+ -- , Font.variant Font.smallCaps
99+ -- , Font.variant Font.ligatures
100+ -- , Font.variant Font.diagonalFractions
101+ ]
102+ (text "Quality 1st Hello stylish friend! ofl 123456 1/3")
103+ , el
104+ [ Background.color (rgba 0 0.9 0.8 1)
105+ , Font.color (rgb 0 0 0)
106+ , behindContent
107+ (el [ Background.color (rgb 0.9 0.9 0), Font.color (rgb 1 1 1) ] (text "hi there"))
108+ , inFront
109+ (el [ Background.color (rgb 0.9 0.9 0.5) ] (text "yo"))
110+
111+ -- , Font.sizeByCapital
112+ -- , Font.variant Font.smallCaps
113+ -- , Font.variant Font.ligatures
114+ -- , Font.variant Font.diagonalFractions
115+ ]
116+ (text "Quality 1st Hello stylish friend! ofl 123456 1/3")
117+ , el
118+ [ Background.color (rgb 0.1 0.1 0.1)
119+ , width (px 200)
120+ , height (px 200)
121+
122+ -- , below
123+ -- (el
124+ -- [ Background.color (rgb 1 0 0)
125+ -- , width (px 20)
126+ -- , height (px 20)
127+ -- , moveDown 30
128+ -- ]
129+ -- none
130+ -- )
131+ , below
132+ (el
133+ [ Background.color (rgb 0.1 0.1 0.6)
134+ , width (px 150)
135+ , height (px 150)
136+
137+ -- , alignBottom
138+ ]
139+ none
140+ )
141+ ]
142+ none
143+ , el
144+ [ Background.color (rgb 0.1 0.1 0.1)
145+ , width (px 200)
146+ , height (px 200)
147+ , onRight
148+ (el
149+ [ Background.color (rgb 1 0 0)
150+ , width (px 20)
151+ , height fill
152+
153+ -- , moveUp 30
154+ ]
155+ none
156+ )
157+
158+ -- , inFront
159+ -- (el
160+ -- [ Background.color (rgb 0.1 0.1 0.6)
161+ -- , width (px 150)
162+ -- , height (px 150)
163+ -- ]
164+ -- none
165+ -- )
166+ -- , above
167+ -- (el
168+ -- [ Background.color (rgb 1 0 0)
169+ -- , width (px 20)
170+ -- , height (px 20)
171+ -- , moveUp 30
172+ -- ]
173+ -- none
174+ -- )
175+ ]
176+ none
177+ ]
178+
179+
180+
181+-- row
182+-- [ --width (px 420)
183+-- padding 0
184+-- , spacing 20
185+-- , Background.color (rgb 0.2 0.2 0.3)
186+-- ]
187+-- [ box
188+-- , box
189+-- , box
190+-- -- , box
191+-- -- , box
192+-- ]
193+-- wrappedRow
194+-- [ width (px 420)
195+-- , padding 10
196+-- , spacing 20
197+-- , Background.color (rgb 0.2 0.2 0.3)
198+-- ]
199+-- [ box
200+-- , box
201+-- , box
202+-- , box
203+-- , box
204+-- ]
deps/elm-ui/experiments/workspace/Table.elmnew file+65
@@ -0,0 +1,65 @@
1+module Main exposing (..)
2+
3+{-| -}
4+
5+import Element exposing (..)
6+import Element.Background as Background
7+import Element.Font as Font
8+import Element.Input
9+import Element.Lazy
10+
11+
12+type alias Person =
13+ { firstName : String
14+ , lastName : String
15+ }
16+
17+
18+persons : List Person
19+persons =
20+ [ { firstName = "David"
21+ , lastName = "Bowie"
22+ }
23+ , { firstName = "Florence"
24+ , lastName = "Welch"
25+ }
26+ ]
27+
28+
29+main =
30+ Element.layout
31+ [ Background.color (rgba 0 0 0 1)
32+ , Font.color (rgba 1 1 1 1)
33+ , Font.italic
34+ , Font.size 32
35+ , Font.family
36+ [ Font.external
37+ { url = "https://fonts.googleapis.com/css?family=EB+Garamond"
38+ , name = "EB Garamond"
39+ }
40+ , Font.sansSerif
41+ ]
42+ ]
43+ <|
44+ Element.table
45+ [ Element.centerX
46+ , Element.centerY
47+ , Element.spacing 5
48+ , Element.padding 10
49+ ]
50+ { data = persons
51+ , columns =
52+ [ { header = Element.text "First Name"
53+ , width = px 200
54+ , view =
55+ \person ->
56+ Element.text person.firstName
57+ }
58+ , { header = Element.text "Last Name"
59+ , width = fill
60+ , view =
61+ \person ->
62+ Element.text person.lastName
63+ }
64+ ]
65+ }
deps/elm-ui/experiments/workspace/elm.jsonnew file+25
@@ -0,0 +1,25 @@
1+{
2+ "type": "application",
3+ "source-directories": [
4+ ".",
5+ "../src/"
6+ ],
7+ "elm-version": "0.19.0",
8+ "dependencies": {
9+ "direct": {
10+ "elm/browser": "1.0.0",
11+ "elm/core": "1.0.0",
12+ "elm/html": "1.0.0",
13+ "elm/json": "1.0.0",
14+ "elm/virtual-dom": "1.0.0"
15+ },
16+ "indirect": {
17+ "elm/time": "1.0.0",
18+ "elm/url": "1.0.0"
19+ }
20+ },
21+ "test-dependencies": {
22+ "direct": {},
23+ "indirect": {}
24+ }
25+}
deps/elm-ui/notes/BENCHMARKS.mdnew file+20
@@ -0,0 +1,20 @@
1+# Render Benchmark
2+
3+```bash
4+# In root directory
5+yarn install
6+yarn bench
7+```
8+
9+We're interested in overall rendering performance. Right now that means measuring:
10+
11+1. Speed for first paint.
12+2. Rerender speed.
13+3. FPS for extended animations.
14+
15+## Some notes about results.
16+
17+- For the extended animation graph, you see it tops out at a certain point. That's when the rendering pipeline is maxed out and it's now going below 60fps.
18+
19+- The html and inline style cases are **not really** directly comparable to the `elm-ui` stuff because they're not buying you the same thing (which is really write-able, maintainable layouts.) However they're nice to see because they're the current limit of elm's rendering.
20+
deps/elm-ui/notes/CHANGES-FROM-STYLE-ELEMENTS.mdnew file+199
@@ -0,0 +1,199 @@
1+# Compared to Style Elements
2+
3+This was a MAJOR rewrite of Style Elements.
4+
5+* **Major Performance improvement** - Style Elements v5 is much faster than v4 due to a better rendering strategy and generating very minimal html. The rewritten architecture also allows me to explore a few other optimizations, so things may get even faster than they are now.
6+
7+* **Lazy is here!** - It works with no weird caveats.
8+
9+## No Stylesheet
10+
11+You now define styles on the element itself.
12+
13+```
14+el [ Background.color blue, Font.color white ] (text "I'm so stylish!")
15+```
16+
17+These styles are gathered and rendered into a `stylesheet`. This has a few advantages:
18+
19+1. Much faster than rendering as actual inline styles
20+2. More expressive power by allowing style-elements compile to pseudoclasses, css animations and the like.
21+3. Defining styles like this is a really nice workflow.
22+
23+## Reorganization
24+
25+* No `Style` modules anymore, it's all under `Element`.
26+* `Style.Color` and `Style.Shadow` have been merged into `Element.Font`, `Element.Border`, and `Element.background`. So things like `Font.color` and `Border.glow` now exist.
27+* No more `Element.Attributes`, everything has been either moved to `Element` or to a more appropriate module.
28+
29+
30+## Wait isn't Style Elements about separation of layout and style?!
31+
32+It was! So why is there only `Element` and no `StyleSheet` now?
33+
34+The key insight is that it's not so much the separation of layout and style that is important as it is that _properties affecting layout should all be in the view function_. The main thing is _not_ having layout specified through several layers of indirection, but having everything explict and in one place.
35+
36+The new version moves to a more refined version of this idea: **Everything should be explicit and in your view!**
37+
38+
39+## Style Organization
40+
41+Your next question might be "if we don't have a stylesheet, how to we capture our style logic in a nice way?"
42+
43+The main thing I've found is that stylesheets in general seem to be pretty hard to maintain. Even well-typed stylesheets that only allow single classes! You have to manage names for everything, and in the case of large style refactors it's not obvious that style classes would be organized the same way.
44+
45+So, I'm not sure that stylesheets or something like stylesheets are the way to go.
46+
47+My current thinking is that you have 2 really powerful methods of capturing your styling logic.
48+
49+1. **Just put it in a view function.** If you have a few button variations you want, just create a function for each variation. You probably don't need a huge number of variations. You don't need to think of it like recreating bootstrap in style-elements.
50+
51+2. **Capture your colors, font sizes, etc.** Create a `Style` module that captures the **values** you use for your styling. Keep your colors there, as well as values for spacing, font names, and font sizes all in one place. You should consider using a scaling function for things like spacing and fontsizes.
52+
53+
54+## Element.Region
55+
56+The `Element.Region` module is now how you can do accessibility markup.
57+
58+You can do this by adding an area notation to an element's attributes.
59+
60+```elm
61+import Element.Region as Region
62+
63+row [ Region.navigation ]
64+ [ --..my navigation links
65+ ]
66+
67+```
68+Or you can make something an `<h1>`
69+
70+```
71+el [ Region.heading 1 ] (text "Super important stuff")
72+
73+```
74+
75+This means your accessibility markup is separate from your layout markup, which turns out to be really nice.
76+
77+
78+
79+## Alignment
80+
81+Alignment got a _bunch_ of attention to make it more powerful and intuitive.
82+
83+* _Alignment_ now applies to the element it's attached to, so Alignment on `row` and `column` does not apply to the children but to the `row` or `column` itself.
84+
85+* _It works everywhere!_ Previously, if you set a child as `alignLeft` in a row, nothing would happen. The main weirdness that had to be resolved is what happens to the other elements when an el in the middle of a row is aligned. The answer I came up with is that it will push other elements to the side.
86+
87+```
88+ alignLeft(pushes element on the left of it, to the left)
89+ | center(is the default now)
90+ | | alignRight
91+ v v v
92+ |-el-|-el-|---------|-el-|---------------|-el-|
93+```
94+
95+Also of note, is that if something is `center`, then it will truly be in the center.
96+
97+* _Centered by Default_ - `el`s are centered by default.
98+
99+
100+## Things that have been removed/deprecated
101+
102+
103+**Percent** - `percent` is no longer there for width/height values. Just use `fill`, because you were probably just using `percent 100`, right? If you really need something like percent, you can manage it pretty easy with `fillPortion`. The main reason this goes away is that `percent` allows you to accidently overflow your element when trying to sum up multiple elements.
104+
105+**Grids** - `grid`, and `namedGrid` are gone. The reason for this is that for 95% of cases, just composing something with `row` and `column` results in _much_ nicer code. I'm open to see arguments for `grid`, but I need to see specific realworld usecases that can't be done using `row` and `column`.
106+
107+**WrappedRows/Columns** - `wrappedRow` and `wrappedColumn` are gone. From what I can see these cases don't show up very often. Removing them allows me to be cleaner with the internal style-elements code as well.
108+
109+**When/WhenJust** - `when` and `whenJust` are removed, though you can easily make a convenience function for yourself! I wanted the library to place an emphasis on common elm constructs instead of library-specific ones. As far as shortcuts, they don't actually save you much anyway.
110+
111+**Full, Spacer** - `full` and `spacer` have been removed in order to follow the libraries priority of explicitness. `full` would override the parents padding, while `spacer` would override the parent's `spacing`. Both can be achieved with the more common primitives of `row`, `column` and `spacing`, and potentially some nesting of layouts.
112+
113+
114+
115+# New Version of the Alpha
116+
117+- `Font.weight` has been removed in favor of `Font.extraBold`, `Font.regular`, `Font.light`, etc. All weights from 100 - 900 are represented.
118+- `Background.image` and `Background.fittedImage` will place a centered background image, instead of anchoring at the top left.
119+- `fill |> minimum 20 |> maximum 200` is now present for `minWidth`, `maxWidth`, `minHeight` and `maxHeight` behavior. It works like fill, but with an optional top and lower bound.
120+- `transparent` - Set an element as transparent. It will take up space, but otherwise be transparent and unclickable.
121+- `alpha` can now be set for an element.
122+- `attribute` has been renamed `htmlAttribute` to better convey what it's used for.
123+- `Element.Area` has been renamed `Element.Region` to avoid confusion with `WAI ARIA` stuff.
124+- `center` has been renamed `centerX`
125+
126+
127+
128+# New Default Behavior
129+
130+The default logic has been made more consistent and hopefully more intuitive.
131+
132+All elements start with `width/height shrink`, which means that they are the size of their contents.
133+
134+
135+# PseudoClass Support
136+
137+`Element.mouseOver`, `Element.focused`, and `Element.mouseDown` are available to style `:hover`, `:focus` and `:active`.
138+
139+Only a small subset of properties are allowed here or else the compiler will give you an error.
140+
141+This also introduced some new type aliases for attributes.
142+
143+`Attribute msg` - What you're used to. This **cannot** be used in a mouseOver/focused/etc.
144+
145+`Attr decorative msg` - A new attribute alias for attributes that can be used as a normal attribute or in `mouseOver`, `focused`, etc. I like to think of this as a *Decorative Attribute*.
146+
147+
148+# Input
149+
150+`Input.select` has been removed. Ultimately this came down to it being recommended against for most UX purposes.
151+
152+If you're looking for a replacement, consider any of these options which will likely create a better experience:
153+
154+- Input.checkbox
155+- Input.radio/Input.radioRow with custom styling
156+- Input.text with some sort of suggestion/autocomplete attached to it.
157+
158+If you still need to have a select menu, you can either:
159+
160+- *Embed one* using `html`
161+- [Craft one by having a hidden `radio` that is shown on focus.](https://gist.github.com/mdgriffith/b99b7ee04eaabaac042572e328a85345) You'll have to store some state that indicates if the menu is open or not, but you'd have to do that anyway if this library was directly supporting `select`.
162+
163+*Input.Notices* have been removed, which includes warnings and errors. Accessibility is important to this library and this change is actually meant to make it easier to have good form validation feedback.
164+
165+You can just use `above`/`below` when you need to show a validation message and it will be announced politely to users using screen readers.
166+
167+Notices were originally annotated as errors or warnings so that `aria-invalid` could be attached. However, it seems to me that having the changes be announced politely is better than having the screen reader just say "Yo, something's invalid". You now have more control over the feedback! Craft your messages well :)
168+
169+
170+Type aliases for the records used for inputs were also removed because it gives a nicer error message which references specific fields instead of the top level type alias.
171+
172+
173+
174+# New Testing Capabilities
175+
176+A test suite of ~1.6k layout tests was written(whew!). All of these tests pass on Chrome, Firefox, Safari, Edge, and IE11.
177+
178+# Overview of other changes
179+
180+- `Font.lineHeight` has been removed. Instead, `spacing` now works on paragraphs.
181+- `Element.empty` has been renamed `Element.none` to be more consistent with other elm libraries.
182+- `Device` no longer includes `window.width` and `window.height`. Previously every view function that depends on `device` was forced to rerender when the window was resized, which meant you couldn't take advantage of lazy. If you do need the window coordinates you can save them separately.
183+- *Fewer nodes rendered* - So, things should be faster!
184+- `fillBetween` has been replaced by `Element.minimum` and `Element.maximum`.
185+
186+So now you can do things like
187+
188+```elm
189+view =
190+ el
191+ [ width
192+ (fill
193+ |> minimum 20
194+ |> maximum 200
195+ )
196+ ]
197+ (text "woohoo, I have a min and max")
198+
199+```
deps/elm-ui/notes/RUNNING_TESTS.mdnew file+65
@@ -0,0 +1,65 @@
1+# Elm UI Test Suite
2+
3+There are two types of tests for Elm UI. The normal kind, which are located in `tests/suite/`
4+
5+These can be run using [`elm-test`](https://github.com/elm-explorations/test) and can be run via
6+
7+```bash
8+# in the root elm-ui directory
9+yarn install # or npm install
10+yarn run test # or npm run test
11+```
12+
13+**Note** you need to be at the `elm-ui` root dir.
14+
15+# Layout Testing
16+
17+`elm-ui` also needs to ensure that all layouts work as expected on all browsers.
18+
19+In order to do this, we need a different testing environment.
20+
21+So, the tests in `elm-ui/tests-rendering/src/Tests` will render output, then harvest bounding boxes form the browser, and run the test on the resulting data.
22+
23+Run this locally via:
24+
25+```bash
26+npm install
27+npm run test-render
28+```
29+
30+**Note** if you run this, it runs by default in headless chrome, so you won't see a browser actually open. Ideally you'll just see something like this:
31+
32+```
33+Compiling tests
34+Done compiling
35+Running locally on Chrome...
36+Local Chrome -> All 18029 tests passed
37+```
38+
39+That's right. We have 18,029 tests. Woohoo!
40+
41+# Running on Sauce Labs
42+
43+In order to automate some of this stuff, this test can be run on Sauce Labs.
44+
45+If you have an account, you'll need to create a `elm-ui/sauce.env` file, which has the following fields:
46+
47+```
48+export SAUCE_ACCESS_KEY={your key}
49+export SAUCE_USERNAME={your username}
50+```
51+
52+You can then run.
53+
54+```bash
55+npm run test-render-sauce
56+```
57+
58+**Note**: The compiled `elm-ui` test needs to be made public somewhere in order for this to work. At the moment it's at my github.io account, though something more permanenet might be set up.
59+
60+
61+# Sauce Labs References
62+
63+https://wiki.saucelabs.com/display/DOCS/Platform+Configurator#/
64+https://wiki.saucelabs.com/display/DOCS/Sauce+Labs+Basics
65+https://github.com/saucelabs-sample-test-frameworks/Python-Pytest-Selenium
deps/elm-ui/notes/classifying-issues.mdnew file+29
@@ -0,0 +1,29 @@
1+# Classifying Issues
2+
3+
4+One of the first things we want to do is to keep our issues categorized.
5+
6+If you add a comment to an issue that references a label, that label will be assigned to that issue! (e.g. `#has-ellie` will add the `has-ellie` label.)
7+
8+[Here's one that I categorized](https://github.com/mdgriffith/elm-ui/issues/201)
9+
10+[Labels are described here](https://github.com/mdgriffith/elm-ui/labels)
11+
12+- **Feature Suggestions** - `#feature-suggestion` - This issue describes a feature suggestion. Tagging it with `#feature-suggestion` is all that needs to happen.
13+
14+- **Pain Point** - `#pain-point` - This is an issue that descrbes a challenge someone is facing, but makes not direct suggestion about how it should be solved. Here's a good example, [unable to applly text overflow ellipses](https://github.com/mdgriffith/elm-ui/issues/112).
15+
16+- **Bug** - `#bug` - The issue that's being described is potentially a bug. It may not be totally obvious what the fix is.
17+ - **Has Ellie** - `#has-ellie` - Every bug described should have an ellie showing the problem, even if it's sorta trivial.
18+ - **No Ellie** - If it's a bug, but has been checked for ellies and has no ellie, flag it as `#no-ellie`.
19+ - **Has Test** - `#has-test` - Once we have an ellie for the problem, we want a version of that code in the codebase so I can easily take a look.
20+ - The thing to do is to open a PR that copies that ellie into the [`tests-rendering/cases/open`](https://github.com/mdgriffith/elm-ui/tree/master/tests-rendering/cases/open) directory. Give it a succinct, human name.
21+ - Rename the `Element.*` imports as `Testable.Element.*`
22+ - Add a link to the issue, the title of the issue, and the body of the issue to the module comment. [Here's an example](https://github.com/mdgriffith/elm-ui/tree/master/tests-rendering/cases/open/InFrontSize.elm)
23+ - Test is compiling - Optionally you can see if the test is compiling by first `cd tests-rendering` and then running `elm-live cases/open/{The file}.elm --open --dir=view -- --output=view/elm.js --debug`
24+ - If it does not compile, flag the issue as `#test-not-compiling`. Don't worry about fixing it unless it's really obvious what needs to happen.
25+ - Check if the test passes. Do that by opening `tests-rendering/cases/view/view.html` after running the above compilation. If it says all passes, likely you should flag the issue as `#test-incorrectly-passing`.
26+ - If it's failing, you can flag as `#test-failing`
27+
28+
29+
deps/elm-ui/notes/discussion/ColorWithoutAlpha.API.mdnew file+135
@@ -0,0 +1,135 @@
1+# API sketch for separating out alpha from Color
2+
3+**Motivation**
4+
5+If we separate out alpha from the core color type, we can
6+
7+1. Have a unified `Color` type that works in all contexts, including in webGL situations where transparency may be handled differently, or not at all.
8+
9+2. Encourage people to use actual color mixing functions where possible and to enumerate their colors concretely.
10+ - The point here is that color mixing is situation dependent. Why not just mix a color explicitly in a way where you know it looks good?
11+
12+3. With a totally opaque color type, we can calculate contrast for accessibility evaluation easily. An alpha channel means we'd have to emulate browser mixing to do that, which I'm not sure is consistent.
13+
14+Ultimately I want the position of `elm-ui` to be something like the following:
15+
16+1. `rgb`(both value based and hex) is more of an interop format than a color space you'd actually want to modify things in. Think, when have you ever thought "oh, just bump the red channel down a bit and you'll be good"?
17+
18+ - As an interop format, it means it's what you're going to be copying from tools or receiving from a designer.
19+ - These tools generally have the ability to mix things properly.
20+ - By mixing things concretely, designers have more control over their ultimate design.
21+
22+2. Transparency in most of these cases is still necessary or at the least convenient. It's not too difficult to treat that separately than the identity of a color value.
23+
24+3. Ultimately we want to encourage people to use a colorspace like [HSLuv](https://package.elm-lang.org/packages/kuon/elm-hsluv/latest/). Basically any of the colorspaces that are based in [CIEXYZ colorspace](https://en.wikipedia.org/wiki/CIE_1931_color_space). They're much easier to use. - May not really seem related to alpha channels, but the idea is that doing things like `lightening` a color is much easier in these other colorspaces.
25+
26+## Element.Font
27+
28+ Font.color : Color -> Attribute msg
29+
30+ -- Tempted to drop this one.
31+ -- People could still have transparent text using `Element.opacity`
32+ -- if they really want it
33+ Font.opacity : Float -> Attribute msg
34+
35+ Font.shadow :
36+ { offset : (Float, Float)
37+ , blur : Float
38+ , color : Color
39+ , opacity : Float
40+ } -> Attribute msg
41+
42+## Element.Background
43+
44+ Background.color : Color -> Attribute
45+
46+ -- background opacity is commonly used when we have some text
47+ -- over an image background.
48+ Background.opacity : Float -> Attribute
49+
50+For gradients, we can have opacity as a separate set of steps.
51+This actually makes it _easier_ to do something like a rainbow that linearly fades away. We don't have to figure out the exact opacity that the 5th color has.
52+
53+ Background.gradient :
54+ { angle : Float
55+ , colors : List Color
56+ , opacity : List Float
57+ }
58+
59+Do you ever have a gradient with more than two alpha steps?
60+Maybe you'd actually like to adjust the falloff curve instead of have it be linear?
61+Maybe there's an even better way to represent this?
62+
63+ Will eventually want to cover radial gradients, but a similar approach to the above is likely easy.
64+
65+Took a look at [background blend modes](https://developer.mozilla.org/en-US/docs/Web/CSS/background-blend-mode), which can be used to dynamically color images, like the [header image here](https://professional-rentals.com/).
66+
67+The blend modes are influenced by background or element opacity.
68+
69+In that way, we could have something like
70+
71+ Background.blend 0.5 color
72+
73+Which would set a color mode and set the background opacity. I'd need to play around with it, but seems kinda cool!
74+
75+## Element.Border
76+
77+Sometimes a transparent border is used as a placeholder, and then we change a color on `mouseOver`. This is to avoid layout movement in the resulting animation.
78+
79+ Border.color : Color -> Attribute
80+
81+ Border.opacity : Float -> Attribute
82+
83+ Border.shadow :
84+ { offset : (Float, Float)
85+ , size : Float
86+ , blur : Float
87+ , color : Color
88+ , opacity : Float
89+ }
90+
91+ Border.manyShadows :
92+ List
93+ { offset : (Float, Float)
94+ , blur : Float
95+ , color : Color
96+ , opacity : Float
97+ } -> Attribute msg
98+
99+ Border.innerShadow
100+ { offset : ( Float, Float )
101+ , size : Float
102+ , blur : Float
103+ , color : Color
104+ , opacity : Float
105+ }
106+
107+# Discussion and Usecases
108+
109+The main question about binding alpha with color is:
110+
111+ Is the identity of this color an identity about the color and it's ability to mix. Knowing that it's ability to mix in this case is not great.
112+
113+Or would you want to set these things explicitly and independently of each other?
114+
115+## Tinting and shading (i.e. lightening and darkening)
116+
117+_Note_ - not sure what package would house these functions.
118+
119+We usually get in the habit of using alpha for an ad-hoc lightener/darkener.
120+This can easily be replicated with functions that actually operate on colors in elm.
121+
122+ Color.lighten 0.3 color
123+
124+With the idea that this function should use the luminance from CIELUV instead of lightness from hsl.
125+
126+## Mixing two colors
127+
128+We also use alpha as an ad hoc way to mix two colors (i.e. [turn a font subtley green on a green background](https://medium.com/refactoring-ui/7-practical-tips-for-cheating-at-design-40c736799886#9cdf).
129+
130+ el
131+ [ Background.color bg
132+ -- explicitly mix the two!
133+ , Font.color (Color.mix 0.2 white bg)
134+ ]
135+ (text "Howdy")
deps/elm-ui/notes/discussion/ColorWithoutAlpha.mdnew file+67
@@ -0,0 +1,67 @@
1+# A Design for Color without Alpha
2+
3+Color is hard!
4+
5+I've spent a decade and a half in web development and only now feel like I have some sort of handle on it.
6+
7+What I've learned basically comes down to the fact that the two color spaces we're used to dealing with (`rgb` and `hsl`), are not actually that great for thinking about color. Which is unfortunate.
8+
9+So, what can we use instead?
10+
11+Research on color perception in the 1920's led to the development of the [CIEXYZ colorspace](https://en.wikipedia.org/wiki/CIE_1931_color_space), which describes color in a way that is much closer to how humans perceive color. Essentially they were able to model constants in their equations that literally represent some of the built-in values we have as humans to perceive color.
12+
13+How crazy is that?
14+
15+(Skipping over the fact that there is variation in how people perceive color.)
16+
17+There are a number of color spaces that are based on this initial research, including CIELAB(generally recommended for print), and CIELUV(generally recommended for light). They are essentailly different ways to talk about the same color space. Sorta like polar coordinates(r,θ) and cartesian coordiantes (x,y) can both represent a point.
18+
19+The `L` in the above acronyms represents `Luminance`.
20+
21+This is one of the really cool parts. Two colors that have the same `Luminance`, will be equally "bright" to the human eye.
22+
23+You might be thinking "well, what about the `lightness` channel in `HSL`, huh?". Turns out it's not really based on anything!
24+
25+Here are two hsl colors with the same lightness:
26+![](http://lea.verou.me/wp-content/uploads/2020/04/image-4.png)
27+
28+Do they look like the same "brightness"?
29+
30+Unfortunately the L in HSL stands for Lies and we've been misled all along.
31+
32+[This whole article on color spaces is worth a read if you got the time](http://lea.verou.me/2020/04/lch-colors-in-css-what-why-and-how/)
33+
34+
35+Ok, so, luminance is really cool.
36+
37+With a real `Luminance` factor you can
38+ 1. Generate palettes of colors that work together in a consistent manner.
39+ 2. Automatically know the difference in luminance between two colors. Guess what that is. It's a contrast calculation! Like for accessibility! How nice would that be if it was X - Y as opposed to some crazy math?
40+ 3. Get an intuition for how colors will interact with each other.
41+ 4. Generate gradients that aren't unexpectedly broken. (I have some examples of this, I'll dig them up later)
42+ 5. Animate colors consistently. Animating in rgb or hsl will cause color animation to look awful in different ways.
43+
44+It really is a better world.
45+
46+Ok, so how do we get there and what does this mean for elm-ui?
47+
48+
49+# Elm UI stuff
50+
51+The above knowledge is hard won. Many people are not aware that there are better colorspaces than rgb and hsl.
52+
53+Color is hard. In many cases, it will remain hard until people get a nice introduction to something based on CIEXYZ.
54+
55+In elm, [we have a package for HSLuv](
56+https://package.elm-lang.org/packages/kuon/elm-hsluv/latest/), which you can use right now. It's great.
57+
58+However! We have one confouding factor, which is that we're used to bundling an `alpha` value with our colors.
59+
60+The same math that makes rgb and hsl less than great is used to blend colors via alpha.
61+
62+By bundling alpha with color, we're encouranging people to blend colors in an ad-hoc way when we could be providing them avenues to easily do it the right way. We have a whole programming language, we're not confined to only CSS anymore.
63+
64+However! Frontend development also involves talking to designers. Designers usually provide rgb, hsl, or a hex version of rgb.
65+
66+I now sorta view these as *interop formats*.
67+
deps/elm-ui/notes/discussion/Internationalization.mdnew file+13
@@ -0,0 +1,13 @@
1+# Internationalization
2+
3+What are the concerns that `elm-ui` should handle in order to properly support internationalization in an app?
4+
5+# Right-to-Left and Left-to-Right Languages
6+
7+[This talk from Strange Loop is an amazing overview of the concerns for RtL and LtR languages.](https://www.youtube.com/watch?v=xpumLsaAWGw&t=3s) Turns out it can get super crazy!
8+
9+It's also interesting because one of the design decisions in `elm-ui` is to support concrete directions like `alignLeft` and `alignRight` instead of `align-conten: flex-start`.
10+
11+
12+
13+
deps/elm-ui/notes/discussion/PaletteGroups.mdnew file+132
@@ -0,0 +1,132 @@
1+# Mini Palette Experiment
2+
3+`elm-ui` currently implements most things such as layout and style as attributes on a element. These are intended to be explicit so that visiting an element will give you all the information you need to understand how an element is shown.
4+
5+However, this can also mean that Elements gather a lot of attributes and in the effort of capturing a consistent design language you may find yourself repeating a lot of combinations of attributes.
6+
7+Previously a construct like `mix : List (Attribute msg) -> Attribute msg` has been proposed as a way to make things easier, however that opens up a large design space. Developers then have to make the difficult decision about what attributes to group together. That decision is It also would allow intermixing of event handlers with style and layout, which seems weird.
8+
9+As an alternative, we could have specific groupings of attributes that are allowed. Done right, this may solve the problem of the dev having to worry about proper groupings and push them towards thinking of their design as a cohesive whole.
10+
11+My intuition says that these groupings will fall along the lines of the current module organization. Here are the helper functions that come to mind. These would be in addition to everything we already have.
12+
13+
14+## Spacing Palette
15+
16+```elm
17+Element.spaceWith :
18+ { padding :
19+ { top : Int
20+ , right : Int
21+ , bottom : Int
22+ , left : Int
23+ }
24+ , spacing :
25+ { x : Int
26+ , y : Int
27+ }
28+ } -> Attribute msg
29+```
30+
31+## Color Palette
32+
33+It might be a little weird to have a color grouping, but my gut says it probably makes sense.
34+
35+By binding background and text color together, we can know all of our background and text color combinations, making it easier to verify and specifiy a minimum contrast for accessibility.
36+
37+```elm
38+Element.colors :
39+ { background : Color
40+ , text : Color
41+ , border : Color
42+ } -> Attribute msg
43+```
44+
45+## Font Palette
46+
47+```elm
48+Element.Font.with :
49+ { typeface : String
50+ , fallback : List String
51+ , scale : Scale
52+ -- adjustments is a new thing that's coming that will allow more precise font sizing.
53+ , adjustments : Maybe Font.Adjustment
54+ -- These are variations like `slash zero`
55+ , variations : List Font.Variation
56+ } -> (Option, Attribute msg)
57+
58+type Scale
59+ = Single Int
60+ | Triple
61+ { small : Int
62+ , normal : Int
63+ , large : Int
64+ }
65+ | Fluid (windowSize -> Scale)
66+
67+
68+
69+
70+-- Usage
71+
72+(titleFont, title) =
73+ Font.with
74+ { typeface = "EB Garamond"
75+ , fallback =
76+ [ "georgia"
77+ , "serif"
78+ ]
79+ , scale =
80+ Font.Triple
81+ { small = 12
82+ , normal = 16
83+ , large = 32
84+ }
85+ , adjustments = Nothing
86+ , variations = []
87+ }
88+
89+
90+view =
91+ Element.layoutWith { options = [ titleFont ] } <|
92+ el
93+ [ title.large
94+ ]
95+ (text "I am a large title font")
96+
97+
98+```
99+
100+## Border Model
101+
102+```elm
103+Element.Border.with :
104+ { width : Int
105+ , style : Border.Style
106+ , rounded :
107+ { topLeft : Int
108+ , topRight : Int
109+ , bottomLeft : Int
110+ , bottomRight : Int
111+ }
112+ }
113+```
114+
115+
116+## Shadow Model
117+
118+This might mean breaking out shadows into their own module.
119+
120+```elm
121+Element.Shadow.stack : List Shadow -> Attribute msg
122+```
123+
124+
125+# General Questions
126+
127+So, here are the questions I have:
128+
129+- If you have a current codebase with `elm-ui`, would this simplify things at all? Is there a way you can quantify it(most elements I have would have half as many attributes)?
130+- Are there alternate groupings that you've come across?
131+
132+
deps/elm-ui/notes/implementation/NEARBY.mdnew file+24
@@ -0,0 +1,24 @@
1+# Rendering Order
2+
3+Nearby elements such as `below`, `above`, and `inFront` are rendered after the other children of the `Element. `behindContent` is rendered before.
4+
5+This is so:
6+
7+- `inFront` doesn't need a special `z-index` to work. This can increase performance because too many `z-index` overrides means shipping more layers to the gpu.
8+- Nearby elements higher up in the DOM hierarchy will be on top of elements lower in the hierarchy. `inFront` on a higher element should be on top of `inFront` elements on a lower element.
9+- Allows nearby elements to be affected by `focused` for `Input`, because they can be reached by a sibling selector. `.focuesed:focus ~ .focusable-style {}`
10+
11+
12+
13+# Desired Behavior of Nearby Elements
14+
15+
16+
17+- `inFront` on an element will be in front of all children.
18+ - if there's an `inFront` attached to a child, it will be beneath the parent's `inFront`
19+- `behindContent`, likewise, will always be between the background and the element's children.
20+- `onLeft`, `onRight`, `above`, and `below` will be in front of any element they overlap with.
21+ - if an element has an `inFront` and it's neighbor has an `onLeft`, then the `onLeft` element will be on top of the `inFront`.
22+- if `onLeft`, `onRight`, `above`, and `below` on separate elements overlap, source order wins:
23+ - in a row, the one attached to the element farthest to the right wins.
24+ - in a column, the one attached to the element farthest down wins.
deps/elm-ui/notes/research/Accessiblity.mdnew file+9
@@ -0,0 +1,9 @@
1+# Accessibility Resources
2+
3+What are good resources that cover effective techniques for accessibility?
4+
5+This can be talks, articles, papers, blogposts, whatever.
6+
7+Ideally the list here should include a link and a brief description of what's interesting about the resource.
8+
9+**TODO**
deps/elm-ui/notes/research/Compatibility-Android.mdnew file+12
@@ -0,0 +1,12 @@
1+# Android Compatibity
2+
3+I'd love to know how easy or difficlt it would be to use `elm-ui`'s API to generate Android layouts.
4+
5+This document is here to track any research that people want to do into the subject. The idea would be to link to specific Android documentation and/or describe an approach for each concept.
6+
7+
8+Full API coverage would be wonderful, though to here's a good place to start.
9+
10+- Row/Column
11+- Nearby's
12+- Spacing/Padding
deps/elm-ui/notes/research/Compatibility-iOS.mdnew file+12
@@ -0,0 +1,12 @@
1+# iOS API Compatibility
2+
3+I'd love to know how easy or difficlt it would be to use `elm-ui`'s API to generate iOS layouts.
4+
5+This document is here to track any research that people want to do into the subject. The idea would be to link to specific iOS documentation and/or describe an approach for each concept.
6+
7+
8+Full API coverage would be wonderful, though to here's a good place to start.
9+
10+- Row/Column
11+- Nearby's
12+- Spacing/Padding
deps/elm-ui/notes/research/Internationalization.mdnew file+10
@@ -0,0 +1,10 @@
1+# Internationalization Resources
2+
3+What are good resources that cover effective internationalization techniques?
4+
5+This can be talks, articles, papers, blogposts, whatever.
6+
7+Ideally the list here should include a link and a brief description of what's interesting about the resource.
8+
9+- [How supporting Right-to-Left can expose your bad UX](https://www.youtube.com/watch?v=xpumLsaAWGw&t=3s) - A wonderful talk on Right-to-Left support and how it's not as obvious as it may seem.
10+ - [dir property](https://www.w3.org/International/questions/qa-html-dir)
deps/elm-ui/package-lock.jsonnew file+1235
@@ -0,0 +1,1235 @@
1+{
2+ "name": "elm-ui-testing",
3+ "version": "1.0.0",
4+ "lockfileVersion": 1,
5+ "requires": true,
6+ "dependencies": {
7+ "ajv": {
8+ "version": "6.12.0",
9+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
10+ "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==",
11+ "requires": {
12+ "fast-deep-equal": "^3.1.1",
13+ "fast-json-stable-stringify": "^2.0.0",
14+ "json-schema-traverse": "^0.4.1",
15+ "uri-js": "^4.2.2"
16+ }
17+ },
18+ "ansi-styles": {
19+ "version": "3.2.1",
20+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
21+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
22+ "requires": {
23+ "color-convert": "^1.9.0"
24+ }
25+ },
26+ "anymatch": {
27+ "version": "3.1.1",
28+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
29+ "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
30+ "requires": {
31+ "normalize-path": "^3.0.0",
32+ "picomatch": "^2.0.4"
33+ }
34+ },
35+ "asn1": {
36+ "version": "0.2.4",
37+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
38+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
39+ "requires": {
40+ "safer-buffer": "~2.1.0"
41+ }
42+ },
43+ "assert-plus": {
44+ "version": "1.0.0",
45+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
46+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
47+ },
48+ "asynckit": {
49+ "version": "0.4.0",
50+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
51+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
52+ },
53+ "aws-sign2": {
54+ "version": "0.7.0",
55+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
56+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
57+ },
58+ "aws4": {
59+ "version": "1.9.1",
60+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
61+ "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug=="
62+ },
63+ "balanced-match": {
64+ "version": "1.0.0",
65+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
66+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
67+ },
68+ "bcrypt-pbkdf": {
69+ "version": "1.0.2",
70+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
71+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
72+ "requires": {
73+ "tweetnacl": "^0.14.3"
74+ }
75+ },
76+ "binary": {
77+ "version": "0.3.0",
78+ "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
79+ "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=",
80+ "requires": {
81+ "buffers": "~0.1.1",
82+ "chainsaw": "~0.1.0"
83+ }
84+ },
85+ "binary-extensions": {
86+ "version": "2.0.0",
87+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
88+ "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow=="
89+ },
90+ "binwrap": {
91+ "version": "0.2.2",
92+ "resolved": "https://registry.npmjs.org/binwrap/-/binwrap-0.2.2.tgz",
93+ "integrity": "sha512-Y+Wvypk3JhH5GPZAvlwJAWOVH/OsOhQMSj37vySuWHwQivoALplPxfBA8b973rFJI7OS+O+1YmmYXIiEXVMAcw==",
94+ "requires": {
95+ "mustache": "^3.0.1",
96+ "request": "^2.88.0",
97+ "request-promise": "^4.2.4",
98+ "tar": "^4.4.10",
99+ "unzip-stream": "^0.3.0"
100+ }
101+ },
102+ "bluebird": {
103+ "version": "3.7.2",
104+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
105+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
106+ },
107+ "brace-expansion": {
108+ "version": "1.1.11",
109+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
110+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
111+ "requires": {
112+ "balanced-match": "^1.0.0",
113+ "concat-map": "0.0.1"
114+ }
115+ },
116+ "braces": {
117+ "version": "3.0.2",
118+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
119+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
120+ "requires": {
121+ "fill-range": "^7.0.1"
122+ }
123+ },
124+ "buffers": {
125+ "version": "0.1.1",
126+ "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
127+ "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s="
128+ },
129+ "caseless": {
130+ "version": "0.12.0",
131+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
132+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
133+ },
134+ "chainsaw": {
135+ "version": "0.1.0",
136+ "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
137+ "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=",
138+ "requires": {
139+ "traverse": ">=0.3.0 <0.4"
140+ }
141+ },
142+ "chalk": {
143+ "version": "2.4.2",
144+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
145+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
146+ "requires": {
147+ "ansi-styles": "^3.2.1",
148+ "escape-string-regexp": "^1.0.5",
149+ "supports-color": "^5.3.0"
150+ },
151+ "dependencies": {
152+ "has-flag": {
153+ "version": "3.0.0",
154+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
155+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
156+ },
157+ "supports-color": {
158+ "version": "5.5.0",
159+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
160+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
161+ "requires": {
162+ "has-flag": "^3.0.0"
163+ }
164+ }
165+ }
166+ },
167+ "chokidar": {
168+ "version": "3.3.0",
169+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz",
170+ "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==",
171+ "requires": {
172+ "anymatch": "~3.1.1",
173+ "braces": "~3.0.2",
174+ "fsevents": "~2.1.1",
175+ "glob-parent": "~5.1.0",
176+ "is-binary-path": "~2.1.0",
177+ "is-glob": "~4.0.1",
178+ "normalize-path": "~3.0.0",
179+ "readdirp": "~3.2.0"
180+ }
181+ },
182+ "chownr": {
183+ "version": "1.1.4",
184+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
185+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
186+ },
187+ "color-convert": {
188+ "version": "1.9.3",
189+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
190+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
191+ "requires": {
192+ "color-name": "1.1.3"
193+ }
194+ },
195+ "color-name": {
196+ "version": "1.1.3",
197+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
198+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
199+ },
200+ "combined-stream": {
201+ "version": "1.0.8",
202+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
203+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
204+ "requires": {
205+ "delayed-stream": "~1.0.0"
206+ }
207+ },
208+ "commander": {
209+ "version": "2.20.0",
210+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
211+ "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ=="
212+ },
213+ "concat-map": {
214+ "version": "0.0.1",
215+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
216+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
217+ },
218+ "core-util-is": {
219+ "version": "1.0.2",
220+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
221+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
222+ },
223+ "cross-spawn": {
224+ "version": "6.0.5",
225+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
226+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
227+ "requires": {
228+ "nice-try": "^1.0.4",
229+ "path-key": "^2.0.1",
230+ "semver": "^5.5.0",
231+ "shebang-command": "^1.2.0",
232+ "which": "^1.2.9"
233+ }
234+ },
235+ "dashdash": {
236+ "version": "1.14.1",
237+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
238+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
239+ "requires": {
240+ "assert-plus": "^1.0.0"
241+ }
242+ },
243+ "delayed-stream": {
244+ "version": "1.0.0",
245+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
246+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
247+ },
248+ "ecc-jsbn": {
249+ "version": "0.1.2",
250+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
251+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
252+ "requires": {
253+ "jsbn": "~0.1.0",
254+ "safer-buffer": "^2.1.0"
255+ }
256+ },
257+ "elm": {
258+ "version": "0.19.1-3",
259+ "resolved": "https://registry.npmjs.org/elm/-/elm-0.19.1-3.tgz",
260+ "integrity": "sha512-6y36ewCcVmTOx8lj7cKJs3bhI5qMfoVEigePZ9PhEUNKpwjjML/pU2u2YSpHVAznuCcojoF6KIsrS1Ci7GtVaQ==",
261+ "requires": {
262+ "request": "^2.88.0"
263+ }
264+ },
265+ "elm-test": {
266+ "version": "0.19.1-revision2",
267+ "resolved": "https://registry.npmjs.org/elm-test/-/elm-test-0.19.1-revision2.tgz",
268+ "integrity": "sha512-zVs2mVeyIE+K9y7/8b333h5xRMDWAoqbBDm7ThLDhyTi7ICxeL3t5uOS4KZCrRk9+4sP6+voSbcBlgr46Q+GiQ==",
269+ "requires": {
270+ "chalk": "3.0.0",
271+ "chokidar": "3.3.0",
272+ "cross-spawn": "7.0.1",
273+ "elmi-to-json": "1.3.0",
274+ "find-parent-dir": "^0.3.0",
275+ "firstline": "2.0.2",
276+ "fs-extra": "8.1.0",
277+ "glob": "7.1.6",
278+ "lodash": "4.17.15",
279+ "minimist": "^1.2.0",
280+ "murmur-hash-js": "1.0.0",
281+ "node-elm-compiler": "5.0.4",
282+ "split": "1.0.1",
283+ "supports-color": "7.1.0",
284+ "temp": "0.9.1",
285+ "which": "2.0.1",
286+ "xmlbuilder": "^13.0.2"
287+ },
288+ "dependencies": {
289+ "ansi-styles": {
290+ "version": "4.2.1",
291+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
292+ "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
293+ "requires": {
294+ "@types/color-name": "^1.1.1",
295+ "color-convert": "^2.0.1"
296+ },
297+ "dependencies": {
298+ "@types/color-name": {
299+ "version": "1.1.1",
300+ "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
301+ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
302+ }
303+ }
304+ },
305+ "chalk": {
306+ "version": "3.0.0",
307+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
308+ "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
309+ "requires": {
310+ "ansi-styles": "^4.1.0",
311+ "supports-color": "^7.1.0"
312+ }
313+ },
314+ "color-convert": {
315+ "version": "2.0.1",
316+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
317+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
318+ "requires": {
319+ "color-name": "~1.1.4"
320+ }
321+ },
322+ "color-name": {
323+ "version": "1.1.4",
324+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
325+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
326+ },
327+ "cross-spawn": {
328+ "version": "7.0.1",
329+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz",
330+ "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==",
331+ "requires": {
332+ "path-key": "^3.1.0",
333+ "shebang-command": "^2.0.0",
334+ "which": "^2.0.1"
335+ },
336+ "dependencies": {
337+ "path-key": {
338+ "version": "3.1.1",
339+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
340+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
341+ },
342+ "shebang-command": {
343+ "version": "2.0.0",
344+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
345+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
346+ "requires": {
347+ "shebang-regex": "^3.0.0"
348+ }
349+ }
350+ }
351+ },
352+ "find-elm-dependencies": {
353+ "version": "2.0.2",
354+ "resolved": "https://registry.npmjs.org/find-elm-dependencies/-/find-elm-dependencies-2.0.2.tgz",
355+ "integrity": "sha512-nM5UCbccD1G8CGK2GsM7ykG3ksOAl9E+34jiDfl07CAl2OPnLpBVWY2hlxEmIkSBfdJjSopEowWHrO0cI8RhxQ==",
356+ "requires": {
357+ "firstline": "1.2.0",
358+ "lodash": "4.17.15"
359+ },
360+ "dependencies": {
361+ "firstline": {
362+ "version": "1.2.0",
363+ "resolved": "https://registry.npmjs.org/firstline/-/firstline-1.2.0.tgz",
364+ "integrity": "sha1-yfSIbn9/vwr8EtcZQdzgaxkq6gU="
365+ }
366+ }
367+ },
368+ "firstline": {
369+ "version": "2.0.2",
370+ "resolved": "https://registry.npmjs.org/firstline/-/firstline-2.0.2.tgz",
371+ "integrity": "sha512-8KcmfI0jgSECnzdhucm0i7vrwef3BWwgjimW2YkRC5eSFwjb5DibVoA0YvgkYwwxuJi9c+7M7X3b3lX8o9B6wg=="
372+ },
373+ "lodash": {
374+ "version": "4.17.15",
375+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
376+ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
377+ },
378+ "node-elm-compiler": {
379+ "version": "5.0.4",
380+ "resolved": "https://registry.npmjs.org/node-elm-compiler/-/node-elm-compiler-5.0.4.tgz",
381+ "integrity": "sha512-VQsT8QSierYGkHzRed+b4MnccQVF1+qPHunE8jBoU7jD6YpuRqCDPzEoC2zfyEJS80qVnlMZrqobLnyjzX9lJg==",
382+ "requires": {
383+ "cross-spawn": "6.0.5",
384+ "find-elm-dependencies": "2.0.2",
385+ "lodash": "4.17.15",
386+ "temp": "^0.9.0"
387+ },
388+ "dependencies": {
389+ "cross-spawn": {
390+ "version": "6.0.5",
391+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
392+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
393+ "requires": {
394+ "nice-try": "^1.0.4",
395+ "path-key": "^2.0.1",
396+ "semver": "^5.5.0",
397+ "shebang-command": "^1.2.0",
398+ "which": "^1.2.9"
399+ }
400+ },
401+ "nice-try": {
402+ "version": "1.0.5",
403+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
404+ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
405+ },
406+ "path-key": {
407+ "version": "2.0.1",
408+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
409+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
410+ },
411+ "semver": {
412+ "version": "5.7.1",
413+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
414+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
415+ },
416+ "shebang-command": {
417+ "version": "1.2.0",
418+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
419+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
420+ "requires": {
421+ "shebang-regex": "^1.0.0"
422+ }
423+ },
424+ "shebang-regex": {
425+ "version": "1.0.0",
426+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
427+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
428+ },
429+ "which": {
430+ "version": "1.3.1",
431+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
432+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
433+ "requires": {
434+ "isexe": "^2.0.0"
435+ }
436+ }
437+ }
438+ },
439+ "supports-color": {
440+ "version": "7.1.0",
441+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
442+ "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
443+ "requires": {
444+ "has-flag": "^4.0.0"
445+ }
446+ },
447+ "temp": {
448+ "version": "0.9.1",
449+ "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.1.tgz",
450+ "integrity": "sha512-WMuOgiua1xb5R56lE0eH6ivpVmg/lq2OHm4+LtT/xtEtPQ+sz6N3bBM6WZ5FvO1lO4IKIOb43qnhoc4qxP5OeA==",
451+ "requires": {
452+ "rimraf": "~2.6.2"
453+ }
454+ },
455+ "which": {
456+ "version": "2.0.1",
457+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.1.tgz",
458+ "integrity": "sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w==",
459+ "requires": {
460+ "isexe": "^2.0.0"
461+ }
462+ }
463+ }
464+ },
465+ "elmi-to-json": {
466+ "version": "1.3.0",
467+ "resolved": "https://registry.npmjs.org/elmi-to-json/-/elmi-to-json-1.3.0.tgz",
468+ "integrity": "sha512-6m1D5/Pb5pUrSOOBgRG3fE2mK19nhmLgZ16jj2KWTVIhT+0GIBuDI1iV0Fee27CZH790J7uMcdGWJ7fnVvpsKg==",
469+ "requires": {
470+ "binwrap": "0.2.2"
471+ }
472+ },
473+ "escape-string-regexp": {
474+ "version": "1.0.5",
475+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
476+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
477+ },
478+ "extend": {
479+ "version": "3.0.2",
480+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
481+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
482+ },
483+ "extsprintf": {
484+ "version": "1.3.0",
485+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
486+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
487+ },
488+ "fast-deep-equal": {
489+ "version": "3.1.1",
490+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
491+ "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
492+ },
493+ "fast-json-stable-stringify": {
494+ "version": "2.1.0",
495+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
496+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
497+ },
498+ "fill-range": {
499+ "version": "7.0.1",
500+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
501+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
502+ "requires": {
503+ "to-regex-range": "^5.0.1"
504+ }
505+ },
506+ "find-elm-dependencies": {
507+ "version": "2.0.2",
508+ "resolved": "https://registry.npmjs.org/find-elm-dependencies/-/find-elm-dependencies-2.0.2.tgz",
509+ "integrity": "sha512-nM5UCbccD1G8CGK2GsM7ykG3ksOAl9E+34jiDfl07CAl2OPnLpBVWY2hlxEmIkSBfdJjSopEowWHrO0cI8RhxQ==",
510+ "requires": {
511+ "firstline": "1.2.0",
512+ "lodash": "4.17.15"
513+ }
514+ },
515+ "find-parent-dir": {
516+ "version": "0.3.0",
517+ "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz",
518+ "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ="
519+ },
520+ "firstline": {
521+ "version": "1.2.0",
522+ "resolved": "https://registry.npmjs.org/firstline/-/firstline-1.2.0.tgz",
523+ "integrity": "sha1-yfSIbn9/vwr8EtcZQdzgaxkq6gU="
524+ },
525+ "forever-agent": {
526+ "version": "0.6.1",
527+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
528+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
529+ },
530+ "form-data": {
531+ "version": "2.3.3",
532+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
533+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
534+ "requires": {
535+ "asynckit": "^0.4.0",
536+ "combined-stream": "^1.0.6",
537+ "mime-types": "^2.1.12"
538+ }
539+ },
540+ "fs-extra": {
541+ "version": "8.1.0",
542+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
543+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
544+ "requires": {
545+ "graceful-fs": "^4.2.0",
546+ "jsonfile": "^4.0.0",
547+ "universalify": "^0.1.0"
548+ }
549+ },
550+ "fs-minipass": {
551+ "version": "1.2.7",
552+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
553+ "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
554+ "requires": {
555+ "minipass": "^2.6.0"
556+ }
557+ },
558+ "fs.realpath": {
559+ "version": "1.0.0",
560+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
561+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
562+ },
563+ "fsevents": {
564+ "version": "2.1.2",
565+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz",
566+ "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==",
567+ "optional": true
568+ },
569+ "getpass": {
570+ "version": "0.1.7",
571+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
572+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
573+ "requires": {
574+ "assert-plus": "^1.0.0"
575+ }
576+ },
577+ "glob": {
578+ "version": "7.1.6",
579+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
580+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
581+ "requires": {
582+ "fs.realpath": "^1.0.0",
583+ "inflight": "^1.0.4",
584+ "inherits": "2",
585+ "minimatch": "^3.0.4",
586+ "once": "^1.3.0",
587+ "path-is-absolute": "^1.0.0"
588+ }
589+ },
590+ "glob-parent": {
591+ "version": "5.1.0",
592+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz",
593+ "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==",
594+ "requires": {
595+ "is-glob": "^4.0.1"
596+ }
597+ },
598+ "graceful-fs": {
599+ "version": "4.2.3",
600+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
601+ "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
602+ },
603+ "har-schema": {
604+ "version": "2.0.0",
605+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
606+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
607+ },
608+ "har-validator": {
609+ "version": "5.1.3",
610+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
611+ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
612+ "requires": {
613+ "ajv": "^6.5.5",
614+ "har-schema": "^2.0.0"
615+ }
616+ },
617+ "has-flag": {
618+ "version": "4.0.0",
619+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
620+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
621+ },
622+ "http-signature": {
623+ "version": "1.2.0",
624+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
625+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
626+ "requires": {
627+ "assert-plus": "^1.0.0",
628+ "jsprim": "^1.2.2",
629+ "sshpk": "^1.7.0"
630+ }
631+ },
632+ "immediate": {
633+ "version": "3.0.6",
634+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
635+ "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
636+ },
637+ "inflight": {
638+ "version": "1.0.6",
639+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
640+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
641+ "requires": {
642+ "once": "^1.3.0",
643+ "wrappy": "1"
644+ }
645+ },
646+ "inherits": {
647+ "version": "2.0.4",
648+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
649+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
650+ },
651+ "is-binary-path": {
652+ "version": "2.1.0",
653+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
654+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
655+ "requires": {
656+ "binary-extensions": "^2.0.0"
657+ }
658+ },
659+ "is-extglob": {
660+ "version": "2.1.1",
661+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
662+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
663+ },
664+ "is-glob": {
665+ "version": "4.0.1",
666+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
667+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
668+ "requires": {
669+ "is-extglob": "^2.1.1"
670+ }
671+ },
672+ "is-number": {
673+ "version": "7.0.0",
674+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
675+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
676+ },
677+ "is-typedarray": {
678+ "version": "1.0.0",
679+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
680+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
681+ },
682+ "isarray": {
683+ "version": "1.0.0",
684+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
685+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
686+ },
687+ "isexe": {
688+ "version": "2.0.0",
689+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
690+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
691+ },
692+ "isstream": {
693+ "version": "0.1.2",
694+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
695+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
696+ },
697+ "jsbn": {
698+ "version": "0.1.1",
699+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
700+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
701+ },
702+ "json-schema": {
703+ "version": "0.2.3",
704+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
705+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
706+ },
707+ "json-schema-traverse": {
708+ "version": "0.4.1",
709+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
710+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
711+ },
712+ "json-stringify-safe": {
713+ "version": "5.0.1",
714+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
715+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
716+ },
717+ "jsonfile": {
718+ "version": "4.0.0",
719+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
720+ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
721+ "requires": {
722+ "graceful-fs": "^4.1.6"
723+ }
724+ },
725+ "jsprim": {
726+ "version": "1.4.1",
727+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
728+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
729+ "requires": {
730+ "assert-plus": "1.0.0",
731+ "extsprintf": "1.3.0",
732+ "json-schema": "0.2.3",
733+ "verror": "1.10.0"
734+ }
735+ },
736+ "jszip": {
737+ "version": "3.4.0",
738+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.4.0.tgz",
739+ "integrity": "sha512-gZAOYuPl4EhPTXT0GjhI3o+ZAz3su6EhLrKUoAivcKqyqC7laS5JEv4XWZND9BgcDcF83vI85yGbDmDR6UhrIg==",
740+ "requires": {
741+ "lie": "~3.3.0",
742+ "pako": "~1.0.2",
743+ "readable-stream": "~2.3.6",
744+ "set-immediate-shim": "~1.0.1"
745+ }
746+ },
747+ "lie": {
748+ "version": "3.3.0",
749+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
750+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
751+ "requires": {
752+ "immediate": "~3.0.5"
753+ }
754+ },
755+ "lodash": {
756+ "version": "4.17.15",
757+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
758+ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
759+ },
760+ "mime-db": {
761+ "version": "1.43.0",
762+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
763+ "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ=="
764+ },
765+ "mime-types": {
766+ "version": "2.1.26",
767+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
768+ "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
769+ "requires": {
770+ "mime-db": "1.43.0"
771+ }
772+ },
773+ "minimatch": {
774+ "version": "3.0.4",
775+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
776+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
777+ "requires": {
778+ "brace-expansion": "^1.1.7"
779+ }
780+ },
781+ "minimist": {
782+ "version": "1.2.4",
783+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.4.tgz",
784+ "integrity": "sha512-wTiNDqe4D2rbTJGZk1qcdZgFtY0/r+iuE6GDT7V0/+Gu5MLpIDm4+CssDECR79OJs/OxLPXMzdxy153b5Qy3hg=="
785+ },
786+ "minipass": {
787+ "version": "2.9.0",
788+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
789+ "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
790+ "requires": {
791+ "safe-buffer": "^5.1.2",
792+ "yallist": "^3.0.0"
793+ }
794+ },
795+ "minizlib": {
796+ "version": "1.3.3",
797+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
798+ "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
799+ "requires": {
800+ "minipass": "^2.9.0"
801+ }
802+ },
803+ "mkdirp": {
804+ "version": "0.5.5",
805+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
806+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
807+ "requires": {
808+ "minimist": "^1.2.5"
809+ },
810+ "dependencies": {
811+ "minimist": {
812+ "version": "1.2.5",
813+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
814+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
815+ }
816+ }
817+ },
818+ "murmur-hash-js": {
819+ "version": "1.0.0",
820+ "resolved": "https://registry.npmjs.org/murmur-hash-js/-/murmur-hash-js-1.0.0.tgz",
821+ "integrity": "sha1-UEEEkmnJZjPIZjhpYLL0KJ515bA="
822+ },
823+ "mustache": {
824+ "version": "3.2.1",
825+ "resolved": "https://registry.npmjs.org/mustache/-/mustache-3.2.1.tgz",
826+ "integrity": "sha512-RERvMFdLpaFfSRIEe632yDm5nsd0SDKn8hGmcUwswnyiE5mtdZLDybtHAz6hjJhawokF0hXvGLtx9mrQfm6FkA=="
827+ },
828+ "nice-try": {
829+ "version": "1.0.5",
830+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
831+ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
832+ },
833+ "node-elm-compiler": {
834+ "version": "5.0.4",
835+ "resolved": "https://registry.npmjs.org/node-elm-compiler/-/node-elm-compiler-5.0.4.tgz",
836+ "integrity": "sha512-VQsT8QSierYGkHzRed+b4MnccQVF1+qPHunE8jBoU7jD6YpuRqCDPzEoC2zfyEJS80qVnlMZrqobLnyjzX9lJg==",
837+ "requires": {
838+ "cross-spawn": "6.0.5",
839+ "find-elm-dependencies": "2.0.2",
840+ "lodash": "4.17.15",
841+ "temp": "^0.9.0"
842+ }
843+ },
844+ "normalize-path": {
845+ "version": "3.0.0",
846+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
847+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
848+ },
849+ "oauth-sign": {
850+ "version": "0.9.0",
851+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
852+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
853+ },
854+ "once": {
855+ "version": "1.4.0",
856+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
857+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
858+ "requires": {
859+ "wrappy": "1"
860+ }
861+ },
862+ "os-tmpdir": {
863+ "version": "1.0.2",
864+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
865+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
866+ },
867+ "pako": {
868+ "version": "1.0.11",
869+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
870+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
871+ },
872+ "path-is-absolute": {
873+ "version": "1.0.1",
874+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
875+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
876+ },
877+ "path-key": {
878+ "version": "2.0.1",
879+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
880+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
881+ },
882+ "performance-now": {
883+ "version": "2.1.0",
884+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
885+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
886+ },
887+ "picomatch": {
888+ "version": "2.2.1",
889+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz",
890+ "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA=="
891+ },
892+ "process-nextick-args": {
893+ "version": "2.0.1",
894+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
895+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
896+ },
897+ "psl": {
898+ "version": "1.7.0",
899+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",
900+ "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ=="
901+ },
902+ "punycode": {
903+ "version": "2.1.1",
904+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
905+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
906+ },
907+ "qs": {
908+ "version": "6.5.2",
909+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
910+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
911+ },
912+ "readable-stream": {
913+ "version": "2.3.7",
914+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
915+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
916+ "requires": {
917+ "core-util-is": "~1.0.0",
918+ "inherits": "~2.0.3",
919+ "isarray": "~1.0.0",
920+ "process-nextick-args": "~2.0.0",
921+ "safe-buffer": "~5.1.1",
922+ "string_decoder": "~1.1.1",
923+ "util-deprecate": "~1.0.1"
924+ },
925+ "dependencies": {
926+ "safe-buffer": {
927+ "version": "5.1.2",
928+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
929+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
930+ }
931+ }
932+ },
933+ "readdirp": {
934+ "version": "3.2.0",
935+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz",
936+ "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==",
937+ "requires": {
938+ "picomatch": "^2.0.4"
939+ }
940+ },
941+ "request": {
942+ "version": "2.88.2",
943+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
944+ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
945+ "requires": {
946+ "aws-sign2": "~0.7.0",
947+ "aws4": "^1.8.0",
948+ "caseless": "~0.12.0",
949+ "combined-stream": "~1.0.6",
950+ "extend": "~3.0.2",
951+ "forever-agent": "~0.6.1",
952+ "form-data": "~2.3.2",
953+ "har-validator": "~5.1.3",
954+ "http-signature": "~1.2.0",
955+ "is-typedarray": "~1.0.0",
956+ "isstream": "~0.1.2",
957+ "json-stringify-safe": "~5.0.1",
958+ "mime-types": "~2.1.19",
959+ "oauth-sign": "~0.9.0",
960+ "performance-now": "^2.1.0",
961+ "qs": "~6.5.2",
962+ "safe-buffer": "^5.1.2",
963+ "tough-cookie": "~2.5.0",
964+ "tunnel-agent": "^0.6.0",
965+ "uuid": "^3.3.2"
966+ }
967+ },
968+ "request-promise": {
969+ "version": "4.2.5",
970+ "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.5.tgz",
971+ "integrity": "sha512-ZgnepCykFdmpq86fKGwqntyTiUrHycALuGggpyCZwMvGaZWgxW6yagT0FHkgo5LzYvOaCNvxYwWYIjevSH1EDg==",
972+ "requires": {
973+ "bluebird": "^3.5.0",
974+ "request-promise-core": "1.1.3",
975+ "stealthy-require": "^1.1.1",
976+ "tough-cookie": "^2.3.3"
977+ }
978+ },
979+ "request-promise-core": {
980+ "version": "1.1.3",
981+ "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz",
982+ "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==",
983+ "requires": {
984+ "lodash": "^4.17.15"
985+ }
986+ },
987+ "rimraf": {
988+ "version": "2.6.3",
989+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
990+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
991+ "requires": {
992+ "glob": "^7.1.3"
993+ }
994+ },
995+ "safe-buffer": {
996+ "version": "5.2.0",
997+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
998+ "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
999+ },
1000+ "safer-buffer": {
1001+ "version": "2.1.2",
1002+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1003+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1004+ },
1005+ "selenium-webdriver": {
1006+ "version": "4.0.0-alpha.7",
1007+ "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.7.tgz",
1008+ "integrity": "sha512-D4qnTsyTr91jT8f7MfN+OwY0IlU5+5FmlO5xlgRUV6hDEV8JyYx2NerdTEqDDkNq7RZDYc4VoPALk8l578RBHw==",
1009+ "requires": {
1010+ "jszip": "^3.2.2",
1011+ "rimraf": "^2.7.1",
1012+ "tmp": "0.0.30"
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+ }
1023+ }
1024+ },
1025+ "semver": {
1026+ "version": "5.7.1",
1027+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
1028+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
1029+ },
1030+ "set-immediate-shim": {
1031+ "version": "1.0.1",
1032+ "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
1033+ "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
1034+ },
1035+ "shebang-command": {
1036+ "version": "1.2.0",
1037+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
1038+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
1039+ "requires": {
1040+ "shebang-regex": "^1.0.0"
1041+ },
1042+ "dependencies": {
1043+ "shebang-regex": {
1044+ "version": "1.0.0",
1045+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
1046+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
1047+ }
1048+ }
1049+ },
1050+ "shebang-regex": {
1051+ "version": "3.0.0",
1052+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
1053+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
1054+ },
1055+ "split": {
1056+ "version": "1.0.1",
1057+ "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
1058+ "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
1059+ "requires": {
1060+ "through": "2"
1061+ }
1062+ },
1063+ "sshpk": {
1064+ "version": "1.16.1",
1065+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
1066+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
1067+ "requires": {
1068+ "asn1": "~0.2.3",
1069+ "assert-plus": "^1.0.0",
1070+ "bcrypt-pbkdf": "^1.0.0",
1071+ "dashdash": "^1.12.0",
1072+ "ecc-jsbn": "~0.1.1",
1073+ "getpass": "^0.1.1",
1074+ "jsbn": "~0.1.0",
1075+ "safer-buffer": "^2.0.2",
1076+ "tweetnacl": "~0.14.0"
1077+ }
1078+ },
1079+ "stealthy-require": {
1080+ "version": "1.1.1",
1081+ "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
1082+ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
1083+ },
1084+ "string_decoder": {
1085+ "version": "1.1.1",
1086+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
1087+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
1088+ "requires": {
1089+ "safe-buffer": "~5.1.0"
1090+ },
1091+ "dependencies": {
1092+ "safe-buffer": {
1093+ "version": "5.1.2",
1094+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
1095+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
1096+ }
1097+ }
1098+ },
1099+ "tar": {
1100+ "version": "4.4.13",
1101+ "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
1102+ "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
1103+ "requires": {
1104+ "chownr": "^1.1.1",
1105+ "fs-minipass": "^1.2.5",
1106+ "minipass": "^2.8.6",
1107+ "minizlib": "^1.2.1",
1108+ "mkdirp": "^0.5.0",
1109+ "safe-buffer": "^5.1.2",
1110+ "yallist": "^3.0.3"
1111+ }
1112+ },
1113+ "temp": {
1114+ "version": "0.9.1",
1115+ "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.1.tgz",
1116+ "integrity": "sha512-WMuOgiua1xb5R56lE0eH6ivpVmg/lq2OHm4+LtT/xtEtPQ+sz6N3bBM6WZ5FvO1lO4IKIOb43qnhoc4qxP5OeA==",
1117+ "requires": {
1118+ "rimraf": "~2.6.2"
1119+ }
1120+ },
1121+ "through": {
1122+ "version": "2.3.8",
1123+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
1124+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
1125+ },
1126+ "tmp": {
1127+ "version": "0.0.30",
1128+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz",
1129+ "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=",
1130+ "requires": {
1131+ "os-tmpdir": "~1.0.1"
1132+ }
1133+ },
1134+ "to-regex-range": {
1135+ "version": "5.0.1",
1136+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1137+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1138+ "requires": {
1139+ "is-number": "^7.0.0"
1140+ }
1141+ },
1142+ "tough-cookie": {
1143+ "version": "2.5.0",
1144+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
1145+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
1146+ "requires": {
1147+ "psl": "^1.1.28",
1148+ "punycode": "^2.1.1"
1149+ }
1150+ },
1151+ "traverse": {
1152+ "version": "0.3.9",
1153+ "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
1154+ "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk="
1155+ },
1156+ "tunnel-agent": {
1157+ "version": "0.6.0",
1158+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
1159+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
1160+ "requires": {
1161+ "safe-buffer": "^5.0.1"
1162+ }
1163+ },
1164+ "tweetnacl": {
1165+ "version": "0.14.5",
1166+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
1167+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
1168+ },
1169+ "universalify": {
1170+ "version": "0.1.2",
1171+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
1172+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
1173+ },
1174+ "unzip-stream": {
1175+ "version": "0.3.0",
1176+ "resolved": "https://registry.npmjs.org/unzip-stream/-/unzip-stream-0.3.0.tgz",
1177+ "integrity": "sha512-NG1h/MdGIX3HzyqMjyj1laBCmlPYhcO4xEy7gEqqzGiSLw7XqDQCnY4nYSn5XSaH8mQ6TFkaujrO8d/PIZN85A==",
1178+ "requires": {
1179+ "binary": "^0.3.0",
1180+ "mkdirp": "^0.5.1"
1181+ }
1182+ },
1183+ "uri-js": {
1184+ "version": "4.2.2",
1185+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
1186+ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
1187+ "requires": {
1188+ "punycode": "^2.1.0"
1189+ }
1190+ },
1191+ "util-deprecate": {
1192+ "version": "1.0.2",
1193+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
1194+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
1195+ },
1196+ "uuid": {
1197+ "version": "3.4.0",
1198+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
1199+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
1200+ },
1201+ "verror": {
1202+ "version": "1.10.0",
1203+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
1204+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
1205+ "requires": {
1206+ "assert-plus": "^1.0.0",
1207+ "core-util-is": "1.0.2",
1208+ "extsprintf": "^1.2.0"
1209+ }
1210+ },
1211+ "which": {
1212+ "version": "1.3.1",
1213+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
1214+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
1215+ "requires": {
1216+ "isexe": "^2.0.0"
1217+ }
1218+ },
1219+ "wrappy": {
1220+ "version": "1.0.2",
1221+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1222+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
1223+ },
1224+ "xmlbuilder": {
1225+ "version": "13.0.2",
1226+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz",
1227+ "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ=="
1228+ },
1229+ "yallist": {
1230+ "version": "3.1.1",
1231+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
1232+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
1233+ }
1234+ }
1235+}
deps/elm-ui/package.jsonnew file+34
@@ -0,0 +1,34 @@
1+{
2+ "name": "elm-ui-testing",
3+ "version": "1.0.0",
4+ "description": "Run the Elm UI benchmarks and render tests",
5+ "main": "index.js",
6+ "scripts": {
7+ "test": "elm-test",
8+ "view-test": "node tests-rendering/automation/view.js",
9+ "test-render": "node tests-rendering/automation/run.js --chrome",
10+ "test-render-sauce": "source sauce.env; node tests-rendering/automation/run.js --sauce --headless",
11+ "test-render-sauce-automated": "node tests-rendering/automation/run.js --sauce --headless",
12+ "test-doc-preview": "bash tests-rendering/automation/doc-preview.sh",
13+ "bench": "node benchmarks/runtime/index.js",
14+ "list-issues": "hub issue -f \"%i,%U,%t,'%L'%n\" > issues.csv"
15+ },
16+ "repository": {
17+ "type": "git",
18+ "url": "git+https://github.com/mdgriffith/elm-ui.git"
19+ },
20+ "author": "Matthew Griffith <mdg.griffith@gmail.com> (http://mechanical-elephant.com/)",
21+ "license": "ISC",
22+ "bugs": {
23+ "url": "https://github.com/mdgriffith/elm-ui/issues"
24+ },
25+ "homepage": "https://github.com/mdgriffith/elm-ui#readme",
26+ "dependencies": {
27+ "chalk": "^2.4.2",
28+ "commander": "^2.20.0",
29+ "elm": "^0.19.1-3",
30+ "elm-test": "^0.19.1-revision2",
31+ "node-elm-compiler": "^5.0.4",
32+ "selenium-webdriver": "^4.0.0-alpha.7"
33+ }
34+}
deps/elm-ui/src/Element.elmnew file+1686
@@ -0,0 +1,1686 @@
1+module Element exposing
2+ ( Element, none, text, el
3+ , row, wrappedRow, column
4+ , paragraph, textColumn
5+ , Column, table, IndexedColumn, indexedTable
6+ , Attribute, width, height, Length, px, shrink, fill, fillPortion, maximum, minimum
7+ , explain
8+ , padding, paddingXY, paddingEach
9+ , spacing, spacingXY, spaceEvenly
10+ , centerX, centerY, alignLeft, alignRight, alignTop, alignBottom
11+ , transparent, alpha, pointer
12+ , moveUp, moveDown, moveRight, moveLeft, rotate, scale
13+ , clip, clipX, clipY
14+ , scrollbars, scrollbarX, scrollbarY
15+ , layout, layoutWith, Option, noStaticStyleSheet, forceHover, noHover, focusStyle, FocusStyle
16+ , link, newTabLink, download, downloadAs
17+ , image
18+ , Color, rgba, rgb, rgb255, rgba255, fromRgb, fromRgb255, toRgb
19+ , above, below, onRight, onLeft, inFront, behindContent
20+ , Attr, Decoration, mouseOver, mouseDown, focused
21+ , Device, DeviceClass(..), Orientation(..), classifyDevice
22+ , modular
23+ , map, mapAttribute
24+ , html, htmlAttribute
25+ )
26+
27+{-|
28+
29+
30+# Basic Elements
31+
32+@docs Element, none, text, el
33+
34+
35+# Rows and Columns
36+
37+When we want more than one child on an element, we want to be _specific_ about how they will be laid out.
38+
39+So, the common ways to do that would be `row` and `column`.
40+
41+@docs row, wrappedRow, column
42+
43+
44+# Text Layout
45+
46+Text layout needs some specific considerations.
47+
48+@docs paragraph, textColumn
49+
50+
51+# Data Table
52+
53+@docs Column, table, IndexedColumn, indexedTable
54+
55+
56+# Size
57+
58+@docs Attribute, width, height, Length, px, shrink, fill, fillPortion, maximum, minimum
59+
60+
61+# Debugging
62+
63+@docs explain
64+
65+
66+# Padding and Spacing
67+
68+There's no concept of margin in `elm-ui`, instead we have padding and spacing.
69+
70+Padding is the distance between the outer edge and the content, and spacing is the space between children.
71+
72+So, if we have the following row, with some padding and spacing.
73+
74+ Element.row [ padding 10, spacing 7 ]
75+ [ Element.el [] none
76+ , Element.el [] none
77+ , Element.el [] none
78+ ]
79+
80+Here's what we can expect:
81+
82+![Three boxes spaced 7 pixels apart. There's a 10 pixel distance from the edge of the parent to the boxes.](https://mdgriffith.gitbooks.io/style-elements/content/assets/spacing-400.png)
83+
84+**Note** `spacing` set on a `paragraph`, will set the pixel spacing between lines.
85+
86+@docs padding, paddingXY, paddingEach
87+
88+@docs spacing, spacingXY, spaceEvenly
89+
90+
91+# Alignment
92+
93+Alignment can be used to align an `Element` within another `Element`.
94+
95+ Element.el [ centerX, alignTop ] (text "I'm centered and aligned top!")
96+
97+If alignment is set on elements in a layout such as `row`, then the element will push the other elements in that direction. Here's an example.
98+
99+ Element.row []
100+ [ Element.el [] Element.none
101+ , Element.el [ alignLeft ] Element.none
102+ , Element.el [ centerX ] Element.none
103+ , Element.el [ alignRight ] Element.none
104+ ]
105+
106+will result in a layout like
107+
108+ |-|-| |-| |-|
109+
110+Where there are two elements on the left, one on the right, and one in the center of the space between the elements on the left and right.
111+
112+**Note** For text alignment, check out `Element.Font`!
113+
114+@docs centerX, centerY, alignLeft, alignRight, alignTop, alignBottom
115+
116+
117+# Transparency
118+
119+@docs transparent, alpha, pointer
120+
121+
122+# Adjustment
123+
124+@docs moveUp, moveDown, moveRight, moveLeft, rotate, scale
125+
126+
127+# Clipping and Scrollbars
128+
129+Clip the content if it overflows.
130+
131+@docs clip, clipX, clipY
132+
133+Add a scrollbar if the content is larger than the element.
134+
135+@docs scrollbars, scrollbarX, scrollbarY
136+
137+
138+# Rendering
139+
140+@docs layout, layoutWith, Option, noStaticStyleSheet, forceHover, noHover, focusStyle, FocusStyle
141+
142+
143+# Links
144+
145+@docs link, newTabLink, download, downloadAs
146+
147+
148+# Images
149+
150+@docs image
151+
152+
153+# Color
154+
155+In order to use attributes like `Font.color` and `Background.color`, you'll need to make some colors!
156+
157+@docs Color, rgba, rgb, rgb255, rgba255, fromRgb, fromRgb255, toRgb
158+
159+
160+# Nearby Elements
161+
162+Let's say we want a dropdown menu. Essentially we want to say: _put this element below this other element, but don't affect the layout when you do_.
163+
164+ Element.row []
165+ [ Element.el
166+ [ Element.below (Element.text "I'm below!")
167+ ]
168+ (Element.text "I'm normal!")
169+ ]
170+
171+This will result in
172+
173+ |- I'm normal! -|
174+ I'm below
175+
176+Where `"I'm Below"` doesn't change the size of `Element.row`.
177+
178+This is very useful for things like dropdown menus or tooltips.
179+
180+@docs above, below, onRight, onLeft, inFront, behindContent
181+
182+
183+# Temporary Styling
184+
185+@docs Attr, Decoration, mouseOver, mouseDown, focused
186+
187+
188+# Responsiveness
189+
190+The main technique for responsiveness is to store window size information in your model.
191+
192+Install the `Browser` package, and set up a subscription for [`Browser.Events.onResize`](https://package.elm-lang.org/packages/elm/browser/latest/Browser-Events#onResize).
193+
194+You'll also need to retrieve the initial window size. You can either use [`Browser.Dom.getViewport`](https://package.elm-lang.org/packages/elm/browser/latest/Browser-Dom#getViewport) or pass in `window.innerWidth` and `window.innerHeight` as flags to your program, which is the preferred way. This requires minor setup on the JS side, but allows you to avoid the state where you don't have window info.
195+
196+@docs Device, DeviceClass, Orientation, classifyDevice
197+
198+
199+# Scaling
200+
201+@docs modular
202+
203+
204+## Mapping
205+
206+@docs map, mapAttribute
207+
208+
209+## Compatibility
210+
211+@docs html, htmlAttribute
212+
213+-}
214+
215+import Html exposing (Html)
216+import Html.Attributes
217+import Internal.Flag as Flag exposing (Flag)
218+import Internal.Model as Internal
219+import Internal.Style exposing (classes)
220+
221+
222+{-| -}
223+type alias Color =
224+ Internal.Color
225+
226+
227+{-| Provide the red, green, and blue channels for the color.
228+
229+Each channel takes a value between 0 and 1.
230+
231+-}
232+rgb : Float -> Float -> Float -> Color
233+rgb r g b =
234+ Internal.Rgba r g b 1
235+
236+
237+{-| -}
238+rgba : Float -> Float -> Float -> Float -> Color
239+rgba =
240+ Internal.Rgba
241+
242+
243+{-| Provide the red, green, and blue channels for the color.
244+
245+Each channel takes a value between 0 and 255.
246+
247+-}
248+rgb255 : Int -> Int -> Int -> Color
249+rgb255 red green blue =
250+ Internal.Rgba
251+ (toFloat red / 255)
252+ (toFloat green / 255)
253+ (toFloat blue / 255)
254+ 1
255+
256+
257+{-| -}
258+rgba255 : Int -> Int -> Int -> Float -> Color
259+rgba255 red green blue a =
260+ Internal.Rgba
261+ (toFloat red / 255)
262+ (toFloat green / 255)
263+ (toFloat blue / 255)
264+ a
265+
266+
267+{-| Create a color from an RGB record.
268+-}
269+fromRgb :
270+ { red : Float
271+ , green : Float
272+ , blue : Float
273+ , alpha : Float
274+ }
275+ -> Color
276+fromRgb clr =
277+ Internal.Rgba
278+ clr.red
279+ clr.green
280+ clr.blue
281+ clr.alpha
282+
283+
284+{-| -}
285+fromRgb255 :
286+ { red : Int
287+ , green : Int
288+ , blue : Int
289+ , alpha : Float
290+ }
291+ -> Color
292+fromRgb255 clr =
293+ Internal.Rgba
294+ (toFloat clr.red / 255)
295+ (toFloat clr.green / 255)
296+ (toFloat clr.blue / 255)
297+ clr.alpha
298+
299+
300+{-| Deconstruct a `Color` into its rgb channels.
301+-}
302+toRgb :
303+ Color
304+ ->
305+ { red : Float
306+ , green : Float
307+ , blue : Float
308+ , alpha : Float
309+ }
310+toRgb (Internal.Rgba r g b a) =
311+ { red = r
312+ , green = g
313+ , blue = b
314+ , alpha = a
315+ }
316+
317+
318+{-| The basic building block of your layout.
319+
320+ howdy : Element msg
321+ howdy =
322+ Element.el [] (Element.text "Howdy!")
323+
324+-}
325+type alias Element msg =
326+ Internal.Element msg
327+
328+
329+{-| An attribute that can be attached to an `Element`
330+-}
331+type alias Attribute msg =
332+ Internal.Attribute () msg
333+
334+
335+{-| This is a special attribute that counts as both a `Attribute msg` and a `Decoration`.
336+-}
337+type alias Attr decorative msg =
338+ Internal.Attribute decorative msg
339+
340+
341+{-| Only decorations
342+-}
343+type alias Decoration =
344+ Internal.Attribute Never Never
345+
346+
347+{-| -}
348+html : Html msg -> Element msg
349+html =
350+ Internal.unstyled
351+
352+
353+{-| -}
354+htmlAttribute : Html.Attribute msg -> Attribute msg
355+htmlAttribute =
356+ Internal.Attr
357+
358+
359+{-| -}
360+map : (msg -> msg1) -> Element msg -> Element msg1
361+map =
362+ Internal.map
363+
364+
365+{-| -}
366+mapAttribute : (msg -> msg1) -> Attribute msg -> Attribute msg1
367+mapAttribute =
368+ Internal.mapAttr
369+
370+
371+{-| -}
372+type alias Length =
373+ Internal.Length
374+
375+
376+{-| -}
377+px : Int -> Length
378+px =
379+ Internal.Px
380+
381+
382+{-| Shrink an element to fit its contents.
383+-}
384+shrink : Length
385+shrink =
386+ Internal.Content
387+
388+
389+{-| Fill the available space. The available space will be split evenly between elements that have `width fill`.
390+-}
391+fill : Length
392+fill =
393+ Internal.Fill 1
394+
395+
396+{-| Similarly you can set a minimum boundary.
397+
398+ el
399+ [ height
400+ (fill
401+ |> maximum 300
402+ |> minimum 30
403+ )
404+
405+ ]
406+ (text "I will stop at 300px")
407+
408+-}
409+minimum : Int -> Length -> Length
410+minimum i l =
411+ Internal.Min i l
412+
413+
414+{-| Add a maximum to a length.
415+
416+ el
417+ [ height
418+ (fill
419+ |> maximum 300
420+ )
421+ ]
422+ (text "I will stop at 300px")
423+
424+-}
425+maximum : Int -> Length -> Length
426+maximum i l =
427+ Internal.Max i l
428+
429+
430+{-| Sometimes you may not want to split available space evenly. In this case you can use `fillPortion` to define which elements should have what portion of the available space.
431+
432+So, two elements, one with `width (fillPortion 2)` and one with `width (fillPortion 3)`. The first would get 2 portions of the available space, while the second would get 3.
433+
434+**Also:** `fill == fillPortion 1`
435+
436+-}
437+fillPortion : Int -> Length
438+fillPortion =
439+ Internal.Fill
440+
441+
442+{-| This is your top level node where you can turn `Element` into `Html`.
443+-}
444+layout : List (Attribute msg) -> Element msg -> Html msg
445+layout =
446+ layoutWith { options = [] }
447+
448+
449+{-| -}
450+layoutWith : { options : List Option } -> List (Attribute msg) -> Element msg -> Html msg
451+layoutWith { options } attrs child =
452+ Internal.renderRoot options
453+ (Internal.htmlClass
454+ (String.join " "
455+ [ classes.root
456+ , classes.any
457+ , classes.single
458+ ]
459+ )
460+ :: (Internal.rootStyle ++ attrs)
461+ )
462+ child
463+
464+
465+{-| -}
466+type alias Option =
467+ Internal.Option
468+
469+
470+{-| Elm UI embeds two StyleSheets, one that is constant, and one that changes dynamically based on styles collected from the elements being rendered.
471+
472+This option will stop the static/constant stylesheet from rendering.
473+
474+If you're embedding multiple elm-ui `layout` elements, you need to guarantee that only one is rendering the static style sheet and that it's above all the others in the DOM tree.
475+
476+-}
477+noStaticStyleSheet : Option
478+noStaticStyleSheet =
479+ Internal.RenderModeOption Internal.NoStaticStyleSheet
480+
481+
482+{-| -}
483+defaultFocus :
484+ { borderColor : Maybe Color
485+ , backgroundColor : Maybe Color
486+ , shadow :
487+ Maybe
488+ { color : Color
489+ , offset : ( Int, Int )
490+ , blur : Int
491+ , size : Int
492+ }
493+ }
494+defaultFocus =
495+ Internal.focusDefaultStyle
496+
497+
498+{-| -}
499+type alias FocusStyle =
500+ { borderColor : Maybe Color
501+ , backgroundColor : Maybe Color
502+ , shadow :
503+ Maybe
504+ { color : Color
505+ , offset : ( Int, Int )
506+ , blur : Int
507+ , size : Int
508+ }
509+ }
510+
511+
512+{-| -}
513+focusStyle : FocusStyle -> Option
514+focusStyle =
515+ Internal.FocusStyleOption
516+
517+
518+{-| Disable all `mouseOver` styles.
519+-}
520+noHover : Option
521+noHover =
522+ Internal.HoverOption Internal.NoHover
523+
524+
525+{-| Any `hover` styles, aka attributes with `mouseOver` in the name, will be always turned on.
526+
527+This is useful for when you're targeting a platform that has no mouse, such as mobile.
528+
529+-}
530+forceHover : Option
531+forceHover =
532+ Internal.HoverOption Internal.ForceHover
533+
534+
535+{-| When you want to render exactly nothing.
536+-}
537+none : Element msg
538+none =
539+ Internal.Empty
540+
541+
542+{-| Create some plain text.
543+
544+ text "Hello, you stylish developer!"
545+
546+**Note** text does not wrap by default. In order to get text to wrap, check out `paragraph`!
547+
548+-}
549+text : String -> Element msg
550+text content =
551+ Internal.Text content
552+
553+
554+{-| The basic building block of your layout.
555+
556+You can think of an `el` as a `div`, but it can only have one child.
557+
558+If you want multiple children, you'll need to use something like `row` or `column`
559+
560+ import Element exposing (Element, rgb)
561+ import Element.Background as Background
562+ import Element.Border as Border
563+
564+ myElement : Element msg
565+ myElement =
566+ Element.el
567+ [ Background.color (rgb 0 0.5 0)
568+ , Border.color (rgb 0 0.7 0)
569+ ]
570+ (Element.text "You've made a stylish element!")
571+
572+-}
573+el : List (Attribute msg) -> Element msg -> Element msg
574+el attrs child =
575+ Internal.element
576+ Internal.asEl
577+ Internal.div
578+ (width shrink
579+ :: height shrink
580+ :: attrs
581+ )
582+ (Internal.Unkeyed [ child ])
583+
584+
585+{-| -}
586+row : List (Attribute msg) -> List (Element msg) -> Element msg
587+row attrs children =
588+ Internal.element
589+ Internal.asRow
590+ Internal.div
591+ (Internal.htmlClass (classes.contentLeft ++ " " ++ classes.contentCenterY)
592+ :: width shrink
593+ :: height shrink
594+ :: attrs
595+ )
596+ (Internal.Unkeyed children)
597+
598+
599+{-| -}
600+column : List (Attribute msg) -> List (Element msg) -> Element msg
601+column attrs children =
602+ Internal.element
603+ Internal.asColumn
604+ Internal.div
605+ (Internal.htmlClass
606+ (classes.contentTop
607+ ++ " "
608+ ++ classes.contentLeft
609+ )
610+ :: height shrink
611+ :: width shrink
612+ :: attrs
613+ )
614+ (Internal.Unkeyed children)
615+
616+
617+{-| Same as `row`, but will wrap if it takes up too much horizontal space.
618+-}
619+wrappedRow : List (Attribute msg) -> List (Element msg) -> Element msg
620+wrappedRow attrs children =
621+ let
622+ ( padded, spaced ) =
623+ Internal.extractSpacingAndPadding attrs
624+ in
625+ case spaced of
626+ Nothing ->
627+ Internal.element
628+ Internal.asRow
629+ Internal.div
630+ (Internal.htmlClass
631+ (classes.contentLeft
632+ ++ " "
633+ ++ classes.contentCenterY
634+ ++ " "
635+ ++ classes.wrapped
636+ )
637+ :: width shrink
638+ :: height shrink
639+ :: attrs
640+ )
641+ (Internal.Unkeyed children)
642+
643+ Just (Internal.Spaced spaceName x y) ->
644+ let
645+ newPadding =
646+ case padded of
647+ Just (Internal.Padding name t r b l) ->
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
662+ Just <|
663+ Internal.StyleClass Flag.padding
664+ (Internal.PaddingStyle
665+ (Internal.paddingNameFloat
666+ newTop
667+ newRight
668+ newBottom
669+ newLeft
670+ )
671+ newTop
672+ newRight
673+ newBottom
674+ newLeft
675+ )
676+
677+ else
678+ Nothing
679+
680+ Nothing ->
681+ Nothing
682+ in
683+ case newPadding of
684+ Just pad ->
685+ Internal.element
686+ Internal.asRow
687+ Internal.div
688+ (Internal.htmlClass
689+ (classes.contentLeft
690+ ++ " "
691+ ++ classes.contentCenterY
692+ ++ " "
693+ ++ classes.wrapped
694+ )
695+ :: width shrink
696+ :: height shrink
697+ :: attrs
698+ ++ [ pad ]
699+ )
700+ (Internal.Unkeyed children)
701+
702+ Nothing ->
703+ -- Not enough space in padding to compensate for spacing
704+ let
705+ halfX =
706+ negate (toFloat x / 2)
707+
708+ halfY =
709+ negate (toFloat y / 2)
710+ in
711+ Internal.element
712+ Internal.asEl
713+ Internal.div
714+ attrs
715+ (Internal.Unkeyed
716+ [ Internal.element
717+ Internal.asRow
718+ Internal.div
719+ (Internal.htmlClass
720+ (classes.contentLeft
721+ ++ " "
722+ ++ classes.contentCenterY
723+ ++ " "
724+ ++ classes.wrapped
725+ )
726+ :: Internal.Attr
727+ (Html.Attributes.style "margin"
728+ (String.fromFloat halfY
729+ ++ "px"
730+ ++ " "
731+ ++ String.fromFloat halfX
732+ ++ "px"
733+ )
734+ )
735+ :: Internal.Attr
736+ (Html.Attributes.style "width"
737+ ("calc(100% + "
738+ ++ String.fromInt x
739+ ++ "px)"
740+ )
741+ )
742+ :: Internal.Attr
743+ (Html.Attributes.style "height"
744+ ("calc(100% + "
745+ ++ String.fromInt y
746+ ++ "px)"
747+ )
748+ )
749+ :: Internal.StyleClass Flag.spacing (Internal.SpacingStyle spaceName x y)
750+ :: []
751+ )
752+ (Internal.Unkeyed children)
753+ ]
754+ )
755+
756+
757+{-| This is just an alias for `Debug.todo`
758+-}
759+type alias Todo =
760+ String -> Never
761+
762+
763+{-| Highlight the borders of an element and it's children below. This can really help if you're running into some issue with your layout!
764+
765+**Note** This attribute needs to be handed `Debug.todo` in order to work, even though it won't do anything with it. This is a safety measure so you don't accidently ship code with `explain` in it, as Elm won't compile with `--optimize` if you still have a `Debug` statement in your code.
766+
767+ el
768+ [ Element.explain Debug.todo
769+ ]
770+ (text "Help, I'm being debugged!")
771+
772+-}
773+explain : Todo -> Attribute msg
774+explain _ =
775+ Internal.htmlClass "explain"
776+
777+
778+{-| -}
779+type alias Column record msg =
780+ { header : Element msg
781+ , width : Length
782+ , view : record -> Element msg
783+ }
784+
785+
786+{-| Show some tabular data.
787+
788+Start with a list of records and specify how each column should be rendered.
789+
790+So, if we have a list of `persons`:
791+
792+ type alias Person =
793+ { firstName : String
794+ , lastName : String
795+ }
796+
797+ persons : List Person
798+ persons =
799+ [ { firstName = "David"
800+ , lastName = "Bowie"
801+ }
802+ , { firstName = "Florence"
803+ , lastName = "Welch"
804+ }
805+ ]
806+
807+We could render it using
808+
809+ Element.table []
810+ { data = persons
811+ , columns =
812+ [ { header = Element.text "First Name"
813+ , width = fill
814+ , view =
815+ \person ->
816+ Element.text person.firstName
817+ }
818+ , { header = Element.text "Last Name"
819+ , width = fill
820+ , view =
821+ \person ->
822+ Element.text person.lastName
823+ }
824+ ]
825+ }
826+
827+**Note:** Sometimes you might not have a list of records directly in your model. In this case it can be really nice to write a function that transforms some part of your model into a list of records before feeding it into `Element.table`.
828+
829+-}
830+table :
831+ List (Attribute msg)
832+ ->
833+ { data : List records
834+ , columns : List (Column records msg)
835+ }
836+ -> Element msg
837+table attrs config =
838+ tableHelper attrs
839+ { data = config.data
840+ , columns =
841+ List.map InternalColumn config.columns
842+ }
843+
844+
845+{-| -}
846+type alias IndexedColumn record msg =
847+ { header : Element msg
848+ , width : Length
849+ , view : Int -> record -> Element msg
850+ }
851+
852+
853+{-| Same as `Element.table` except the `view` for each column will also receive the row index as well as the record.
854+-}
855+indexedTable :
856+ List (Attribute msg)
857+ ->
858+ { data : List records
859+ , columns : List (IndexedColumn records msg)
860+ }
861+ -> Element msg
862+indexedTable attrs config =
863+ tableHelper attrs
864+ { data = config.data
865+ , columns =
866+ List.map InternalIndexedColumn config.columns
867+ }
868+
869+
870+{-| -}
871+type alias InternalTable records msg =
872+ { data : List records
873+ , columns : List (InternalTableColumn records msg)
874+ }
875+
876+
877+{-| -}
878+type InternalTableColumn record msg
879+ = InternalIndexedColumn (IndexedColumn record msg)
880+ | InternalColumn (Column record msg)
881+
882+
883+tableHelper : List (Attribute msg) -> InternalTable data msg -> Element msg
884+tableHelper attrs config =
885+ let
886+ ( sX, sY ) =
887+ Internal.getSpacing attrs ( 0, 0 )
888+
889+ columnHeader col =
890+ case col of
891+ InternalIndexedColumn colConfig ->
892+ colConfig.header
893+
894+ InternalColumn colConfig ->
895+ colConfig.header
896+
897+ columnWidth col =
898+ case col of
899+ InternalIndexedColumn colConfig ->
900+ colConfig.width
901+
902+ InternalColumn colConfig ->
903+ colConfig.width
904+
905+ maybeHeaders =
906+ List.map columnHeader config.columns
907+ |> (\headers ->
908+ if List.all ((==) Internal.Empty) headers then
909+ Nothing
910+
911+ else
912+ Just (List.indexedMap (\col header -> onGrid 1 (col + 1) header) headers)
913+ )
914+
915+ template =
916+ Internal.StyleClass Flag.gridTemplate <|
917+ Internal.GridTemplateStyle
918+ { spacing = ( px sX, px sY )
919+ , columns = List.map columnWidth config.columns
920+ , rows = List.repeat (List.length config.data) Internal.Content
921+ }
922+
923+ onGrid rowLevel columnLevel elem =
924+ Internal.element
925+ Internal.asEl
926+ Internal.div
927+ [ Internal.StyleClass Flag.gridPosition
928+ (Internal.GridPosition
929+ { row = rowLevel
930+ , col = columnLevel
931+ , width = 1
932+ , height = 1
933+ }
934+ )
935+ ]
936+ (Internal.Unkeyed [ elem ])
937+
938+ add cell columnConfig cursor =
939+ case columnConfig of
940+ InternalIndexedColumn col ->
941+ { cursor
942+ | elements =
943+ onGrid cursor.row
944+ cursor.column
945+ (col.view
946+ (if maybeHeaders == Nothing then
947+ cursor.row - 1
948+
949+ else
950+ cursor.row - 2
951+ )
952+ cell
953+ )
954+ :: cursor.elements
955+ , column = cursor.column + 1
956+ }
957+
958+ InternalColumn col ->
959+ { elements =
960+ onGrid cursor.row cursor.column (col.view cell)
961+ :: cursor.elements
962+ , column = cursor.column + 1
963+ , row = cursor.row
964+ }
965+
966+ build columns rowData cursor =
967+ let
968+ newCursor =
969+ List.foldl (add rowData)
970+ cursor
971+ columns
972+ in
973+ { elements = newCursor.elements
974+ , row = cursor.row + 1
975+ , column = 1
976+ }
977+
978+ children =
979+ List.foldl (build config.columns)
980+ { elements = []
981+ , row =
982+ if maybeHeaders == Nothing then
983+ 1
984+
985+ else
986+ 2
987+ , column = 1
988+ }
989+ config.data
990+ in
991+ Internal.element
992+ Internal.asGrid
993+ Internal.div
994+ (width fill
995+ :: template
996+ :: attrs
997+ )
998+ (Internal.Unkeyed
999+ (case maybeHeaders of
1000+ Nothing ->
1001+ children.elements
1002+
1003+ Just renderedHeaders ->
1004+ renderedHeaders ++ List.reverse children.elements
1005+ )
1006+ )
1007+
1008+
1009+{-| A paragraph will layout all children as wrapped, inline elements.
1010+
1011+ import Element exposing (el, paragraph, text)
1012+ import Element.Font as Font
1013+
1014+ view =
1015+ paragraph []
1016+ [ text "lots of text ...."
1017+ , el [ Font.bold ] (text "this is bold")
1018+ , text "lots of text ...."
1019+ ]
1020+
1021+This is really useful when you want to markup text by having some parts be bold, or some be links, or whatever you so desire.
1022+
1023+Also, if a child element has `alignLeft` or `alignRight`, then it will be moved to that side and the text will flow around it, (ah yes, `float` behavior).
1024+
1025+This makes it particularly easy to do something like a [dropped capital](https://en.wikipedia.org/wiki/Initial).
1026+
1027+ import Element exposing (alignLeft, el, padding, paragraph, text)
1028+ import Element.Font as Font
1029+
1030+ view =
1031+ paragraph []
1032+ [ el
1033+ [ alignLeft
1034+ , padding 5
1035+ ]
1036+ (text "S")
1037+ , text "o much text ...."
1038+ ]
1039+
1040+Which will look something like
1041+
1042+![A paragraph where the first letter is twice the height of the others](https://mdgriffith.gitbooks.io/style-elements/content/assets/Screen%20Shot%202017-08-25%20at%209.41.52%20PM.png)
1043+
1044+**Note** `spacing` on a paragraph will set the pixel spacing between lines.
1045+
1046+-}
1047+paragraph : List (Attribute msg) -> List (Element msg) -> Element msg
1048+paragraph attrs children =
1049+ Internal.element
1050+ Internal.asParagraph
1051+ Internal.div
1052+ (Internal.Describe Internal.Paragraph
1053+ :: width fill
1054+ :: spacing 5
1055+ :: attrs
1056+ )
1057+ (Internal.Unkeyed children)
1058+
1059+
1060+{-| Now that we have a paragraph, we need some way to attach a bunch of paragraph's together.
1061+
1062+To do that we can use a `textColumn`.
1063+
1064+The main difference between a `column` and a `textColumn` is that `textColumn` will flow the text around elements that have `alignRight` or `alignLeft`, just like we just saw with paragraph.
1065+
1066+In the following example, we have a `textColumn` where one child has `alignLeft`.
1067+
1068+ Element.textColumn [ spacing 10, padding 10 ]
1069+ [ paragraph [] [ text "lots of text ...." ]
1070+ , el [ alignLeft ] none
1071+ , paragraph [] [ text "lots of text ...." ]
1072+ ]
1073+
1074+Which will result in something like:
1075+
1076+![A text layout where an image is on the left.](https://mdgriffith.gitbooks.io/style-elements/content/assets/Screen%20Shot%202017-08-25%20at%208.42.39%20PM.png)
1077+
1078+-}
1079+textColumn : List (Attribute msg) -> List (Element msg) -> Element msg
1080+textColumn attrs children =
1081+ Internal.element
1082+ Internal.asTextColumn
1083+ Internal.div
1084+ (width
1085+ (fill
1086+ |> minimum 500
1087+ |> maximum 750
1088+ )
1089+ :: attrs
1090+ )
1091+ (Internal.Unkeyed children)
1092+
1093+
1094+{-| Both a source and a description are required for images.
1095+
1096+The description is used for people using screen readers.
1097+
1098+Leaving the description blank will cause the image to be ignored by assistive technology. This can make sense for images that are purely decorative and add no additional information.
1099+
1100+So, take a moment to describe your image as you would to someone who has a harder time seeing.
1101+
1102+-}
1103+image : List (Attribute msg) -> { src : String, description : String } -> Element msg
1104+image attrs { src, description } =
1105+ let
1106+ imageAttributes =
1107+ attrs
1108+ |> List.filter
1109+ (\a ->
1110+ case a of
1111+ Internal.Width _ ->
1112+ True
1113+
1114+ Internal.Height _ ->
1115+ True
1116+
1117+ _ ->
1118+ False
1119+ )
1120+ in
1121+ Internal.element
1122+ Internal.asEl
1123+ Internal.div
1124+ (Internal.htmlClass classes.imageContainer
1125+ :: attrs
1126+ )
1127+ (Internal.Unkeyed
1128+ [ Internal.element
1129+ Internal.asEl
1130+ (Internal.NodeName "img")
1131+ ([ Internal.Attr <| Html.Attributes.src src
1132+ , Internal.Attr <| Html.Attributes.alt description
1133+ ]
1134+ ++ imageAttributes
1135+ )
1136+ (Internal.Unkeyed [])
1137+ ]
1138+ )
1139+
1140+
1141+{-|
1142+
1143+ link []
1144+ { url = "http://fruits.com"
1145+ , label = text "A link to my favorite fruit provider."
1146+ }
1147+
1148+-}
1149+link :
1150+ List (Attribute msg)
1151+ ->
1152+ { url : String
1153+ , label : Element msg
1154+ }
1155+ -> Element msg
1156+link attrs { url, label } =
1157+ Internal.element
1158+ Internal.asEl
1159+ (Internal.NodeName "a")
1160+ (Internal.Attr (Html.Attributes.href url)
1161+ :: Internal.Attr (Html.Attributes.rel "noopener noreferrer")
1162+ :: width shrink
1163+ :: height shrink
1164+ :: Internal.htmlClass
1165+ (classes.contentCenterX
1166+ ++ " "
1167+ ++ classes.contentCenterY
1168+ ++ " "
1169+ ++ classes.link
1170+ )
1171+ :: attrs
1172+ )
1173+ (Internal.Unkeyed [ label ])
1174+
1175+
1176+{-| -}
1177+newTabLink :
1178+ List (Attribute msg)
1179+ ->
1180+ { url : String
1181+ , label : Element msg
1182+ }
1183+ -> Element msg
1184+newTabLink attrs { url, label } =
1185+ Internal.element
1186+ Internal.asEl
1187+ (Internal.NodeName "a")
1188+ (Internal.Attr (Html.Attributes.href url)
1189+ :: Internal.Attr (Html.Attributes.rel "noopener noreferrer")
1190+ :: Internal.Attr (Html.Attributes.target "_blank")
1191+ :: width shrink
1192+ :: height shrink
1193+ :: Internal.htmlClass
1194+ (classes.contentCenterX
1195+ ++ " "
1196+ ++ classes.contentCenterY
1197+ ++ " "
1198+ ++ classes.link
1199+ )
1200+ :: attrs
1201+ )
1202+ (Internal.Unkeyed [ label ])
1203+
1204+
1205+{-| A link to download a file.
1206+-}
1207+download :
1208+ List (Attribute msg)
1209+ ->
1210+ { url : String
1211+ , label : Element msg
1212+ }
1213+ -> Element msg
1214+download attrs { url, label } =
1215+ Internal.element
1216+ Internal.asEl
1217+ (Internal.NodeName "a")
1218+ (Internal.Attr (Html.Attributes.href url)
1219+ :: Internal.Attr (Html.Attributes.download "")
1220+ :: width shrink
1221+ :: height shrink
1222+ :: Internal.htmlClass classes.contentCenterX
1223+ :: Internal.htmlClass classes.contentCenterY
1224+ :: attrs
1225+ )
1226+ (Internal.Unkeyed [ label ])
1227+
1228+
1229+{-| A link to download a file, but you can specify the filename.
1230+-}
1231+downloadAs :
1232+ List (Attribute msg)
1233+ ->
1234+ { label : Element msg
1235+ , filename : String
1236+ , url : String
1237+ }
1238+ -> Element msg
1239+downloadAs attrs { url, filename, label } =
1240+ Internal.element
1241+ Internal.asEl
1242+ (Internal.NodeName "a")
1243+ (Internal.Attr (Html.Attributes.href url)
1244+ :: Internal.Attr (Html.Attributes.download filename)
1245+ :: width shrink
1246+ :: height shrink
1247+ :: Internal.htmlClass classes.contentCenterX
1248+ :: Internal.htmlClass classes.contentCenterY
1249+ :: attrs
1250+ )
1251+ (Internal.Unkeyed [ label ])
1252+
1253+
1254+
1255+{- NEARBYS -}
1256+
1257+
1258+createNearby : Internal.Location -> Element msg -> Attribute msg
1259+createNearby loc element =
1260+ case element of
1261+ Internal.Empty ->
1262+ Internal.NoAttribute
1263+
1264+ _ ->
1265+ Internal.Nearby loc element
1266+
1267+
1268+{-| -}
1269+below : Element msg -> Attribute msg
1270+below element =
1271+ createNearby Internal.Below element
1272+
1273+
1274+{-| -}
1275+above : Element msg -> Attribute msg
1276+above element =
1277+ createNearby Internal.Above element
1278+
1279+
1280+{-| -}
1281+onRight : Element msg -> Attribute msg
1282+onRight element =
1283+ createNearby Internal.OnRight element
1284+
1285+
1286+{-| -}
1287+onLeft : Element msg -> Attribute msg
1288+onLeft element =
1289+ createNearby Internal.OnLeft element
1290+
1291+
1292+{-| This will place an element in front of another.
1293+
1294+**Note:** If you use this on a `layout` element, it will place the element as fixed to the viewport which can be useful for modals and overlays.
1295+
1296+-}
1297+inFront : Element msg -> Attribute msg
1298+inFront element =
1299+ createNearby Internal.InFront element
1300+
1301+
1302+{-| This will place an element between the background and the content of an element.
1303+-}
1304+behindContent : Element msg -> Attribute msg
1305+behindContent element =
1306+ createNearby Internal.Behind element
1307+
1308+
1309+{-| -}
1310+width : Length -> Attribute msg
1311+width =
1312+ Internal.Width
1313+
1314+
1315+{-| -}
1316+height : Length -> Attribute msg
1317+height =
1318+ Internal.Height
1319+
1320+
1321+{-| -}
1322+scale : Float -> Attr decorative msg
1323+scale n =
1324+ Internal.TransformComponent Flag.scale (Internal.Scale ( n, n, 1 ))
1325+
1326+
1327+{-| Angle is given in radians. [Here are some conversion functions if you want to use another unit.](https://package.elm-lang.org/packages/elm/core/latest/Basics#degrees)
1328+-}
1329+rotate : Float -> Attr decorative msg
1330+rotate angle =
1331+ Internal.TransformComponent Flag.rotate (Internal.Rotate ( 0, 0, 1 ) angle)
1332+
1333+
1334+{-| -}
1335+moveUp : Float -> Attr decorative msg
1336+moveUp y =
1337+ Internal.TransformComponent Flag.moveY (Internal.MoveY (negate y))
1338+
1339+
1340+{-| -}
1341+moveDown : Float -> Attr decorative msg
1342+moveDown y =
1343+ Internal.TransformComponent Flag.moveY (Internal.MoveY y)
1344+
1345+
1346+{-| -}
1347+moveRight : Float -> Attr decorative msg
1348+moveRight x =
1349+ Internal.TransformComponent Flag.moveX (Internal.MoveX x)
1350+
1351+
1352+{-| -}
1353+moveLeft : Float -> Attr decorative msg
1354+moveLeft x =
1355+ Internal.TransformComponent Flag.moveX (Internal.MoveX (negate x))
1356+
1357+
1358+{-| -}
1359+padding : Int -> Attribute msg
1360+padding x =
1361+ let
1362+ f =
1363+ toFloat x
1364+ in
1365+ Internal.StyleClass Flag.padding (Internal.PaddingStyle ("p-" ++ String.fromInt x) f f f f)
1366+
1367+
1368+{-| Set horizontal and vertical padding.
1369+-}
1370+paddingXY : Int -> Int -> Attribute msg
1371+paddingXY x y =
1372+ if x == y then
1373+ let
1374+ f =
1375+ toFloat x
1376+ in
1377+ Internal.StyleClass Flag.padding (Internal.PaddingStyle ("p-" ++ String.fromInt x) f f f f)
1378+
1379+ else
1380+ let
1381+ xFloat =
1382+ toFloat x
1383+
1384+ yFloat =
1385+ toFloat y
1386+ in
1387+ Internal.StyleClass Flag.padding
1388+ (Internal.PaddingStyle
1389+ ("p-" ++ String.fromInt x ++ "-" ++ String.fromInt y)
1390+ yFloat
1391+ xFloat
1392+ yFloat
1393+ xFloat
1394+ )
1395+
1396+
1397+{-| If you find yourself defining unique paddings all the time, you might consider defining
1398+
1399+ edges =
1400+ { top = 0
1401+ , right = 0
1402+ , bottom = 0
1403+ , left = 0
1404+ }
1405+
1406+And then just do
1407+
1408+ paddingEach { edges | right = 5 }
1409+
1410+-}
1411+paddingEach : { top : Int, right : Int, bottom : Int, left : Int } -> Attribute msg
1412+paddingEach { top, right, bottom, left } =
1413+ if top == right && top == bottom && top == left then
1414+ let
1415+ topFloat =
1416+ toFloat top
1417+ in
1418+ Internal.StyleClass Flag.padding
1419+ (Internal.PaddingStyle ("p-" ++ String.fromInt top)
1420+ topFloat
1421+ topFloat
1422+ topFloat
1423+ topFloat
1424+ )
1425+
1426+ else
1427+ Internal.StyleClass Flag.padding
1428+ (Internal.PaddingStyle
1429+ (Internal.paddingName top right bottom left)
1430+ (toFloat top)
1431+ (toFloat right)
1432+ (toFloat bottom)
1433+ (toFloat left)
1434+ )
1435+
1436+
1437+{-| -}
1438+centerX : Attribute msg
1439+centerX =
1440+ Internal.AlignX Internal.CenterX
1441+
1442+
1443+{-| -}
1444+centerY : Attribute msg
1445+centerY =
1446+ Internal.AlignY Internal.CenterY
1447+
1448+
1449+{-| -}
1450+alignTop : Attribute msg
1451+alignTop =
1452+ Internal.AlignY Internal.Top
1453+
1454+
1455+{-| -}
1456+alignBottom : Attribute msg
1457+alignBottom =
1458+ Internal.AlignY Internal.Bottom
1459+
1460+
1461+{-| -}
1462+alignLeft : Attribute msg
1463+alignLeft =
1464+ Internal.AlignX Internal.Left
1465+
1466+
1467+{-| -}
1468+alignRight : Attribute msg
1469+alignRight =
1470+ Internal.AlignX Internal.Right
1471+
1472+
1473+{-| -}
1474+spaceEvenly : Attribute msg
1475+spaceEvenly =
1476+ Internal.Class Flag.spacing Internal.Style.classes.spaceEvenly
1477+
1478+
1479+{-| -}
1480+spacing : Int -> Attribute msg
1481+spacing x =
1482+ Internal.StyleClass Flag.spacing (Internal.SpacingStyle (Internal.spacingName x x) x x)
1483+
1484+
1485+{-| In the majority of cases you'll just need to use `spacing`, which will work as intended.
1486+
1487+However for some layouts, like `textColumn`, you may want to set a different spacing for the x axis compared to the y axis.
1488+
1489+-}
1490+spacingXY : Int -> Int -> Attribute msg
1491+spacingXY x y =
1492+ Internal.StyleClass Flag.spacing (Internal.SpacingStyle (Internal.spacingName x y) x y)
1493+
1494+
1495+{-| Make an element transparent and have it ignore any mouse or touch events, though it will stil take up space.
1496+-}
1497+transparent : Bool -> Attr decorative msg
1498+transparent on =
1499+ if on then
1500+ Internal.StyleClass Flag.transparency (Internal.Transparency "transparent" 1.0)
1501+
1502+ else
1503+ Internal.StyleClass Flag.transparency (Internal.Transparency "visible" 0.0)
1504+
1505+
1506+{-| A capped value between 0.0 and 1.0, where 0.0 is transparent and 1.0 is fully opaque.
1507+
1508+Semantically equivalent to html opacity.
1509+
1510+-}
1511+alpha : Float -> Attr decorative msg
1512+alpha o =
1513+ let
1514+ transparency =
1515+ o
1516+ |> max 0.0
1517+ |> min 1.0
1518+ |> (\x -> 1 - x)
1519+ in
1520+ Internal.StyleClass Flag.transparency <| Internal.Transparency ("transparency-" ++ Internal.floatClass transparency) transparency
1521+
1522+
1523+
1524+-- {-| -}
1525+-- hidden : Bool -> Attribute msg
1526+-- hidden on =
1527+-- if on then
1528+-- Internal.class "hidden"
1529+-- else
1530+-- Internal.NoAttribute
1531+
1532+
1533+{-| -}
1534+scrollbars : Attribute msg
1535+scrollbars =
1536+ Internal.Class Flag.overflow classes.scrollbars
1537+
1538+
1539+{-| -}
1540+scrollbarY : Attribute msg
1541+scrollbarY =
1542+ Internal.Class Flag.overflow classes.scrollbarsY
1543+
1544+
1545+{-| -}
1546+scrollbarX : Attribute msg
1547+scrollbarX =
1548+ Internal.Class Flag.overflow classes.scrollbarsX
1549+
1550+
1551+{-| -}
1552+clip : Attribute msg
1553+clip =
1554+ Internal.Class Flag.overflow classes.clip
1555+
1556+
1557+{-| -}
1558+clipY : Attribute msg
1559+clipY =
1560+ Internal.Class Flag.overflow classes.clipY
1561+
1562+
1563+{-| -}
1564+clipX : Attribute msg
1565+clipX =
1566+ Internal.Class Flag.overflow classes.clipX
1567+
1568+
1569+{-| Set the cursor to be a pointing hand when it's hovering over this element.
1570+-}
1571+pointer : Attribute msg
1572+pointer =
1573+ Internal.Class Flag.cursor classes.cursorPointer
1574+
1575+
1576+{-| -}
1577+type alias Device =
1578+ { class : DeviceClass
1579+ , orientation : Orientation
1580+ }
1581+
1582+
1583+{-| -}
1584+type DeviceClass
1585+ = Phone
1586+ | Tablet
1587+ | Desktop
1588+ | BigDesktop
1589+
1590+
1591+{-| -}
1592+type Orientation
1593+ = Portrait
1594+ | Landscape
1595+
1596+
1597+{-| Takes in a Window.Size and returns a device profile which can be used for responsiveness.
1598+
1599+If you have more detailed concerns around responsiveness, it probably makes sense to copy this function into your codebase and modify as needed.
1600+
1601+-}
1602+classifyDevice : { window | height : Int, width : Int } -> Device
1603+classifyDevice window =
1604+ -- Tested in this ellie:
1605+ -- https://ellie-app.com/68QM7wLW8b9a1
1606+ { class =
1607+ let
1608+ longSide =
1609+ max window.width window.height
1610+
1611+ shortSide =
1612+ min window.width window.height
1613+ in
1614+ if shortSide < 600 then
1615+ Phone
1616+
1617+ else if longSide <= 1200 then
1618+ Tablet
1619+
1620+ else if longSide > 1200 && longSide <= 1920 then
1621+ Desktop
1622+
1623+ else
1624+ BigDesktop
1625+ , orientation =
1626+ if window.width < window.height then
1627+ Portrait
1628+
1629+ else
1630+ Landscape
1631+ }
1632+
1633+
1634+{-| When designing it's nice to use a modular scale to set spacial rythms.
1635+
1636+ scaled =
1637+ Element.modular 16 1.25
1638+
1639+A modular scale starts with a number, and multiplies it by a ratio a number of times.
1640+Then, when setting font sizes you can use:
1641+
1642+ Font.size (scaled 1) -- results in 16
1643+
1644+ Font.size (scaled 2) -- 16 * 1.25 results in 20
1645+
1646+ Font.size (scaled 4) -- 16 * 1.25 ^ (4 - 1) results in 31.25
1647+
1648+We can also provide negative numbers to scale below 16px.
1649+
1650+ Font.size (scaled -1) -- 16 * 1.25 ^ (-1) results in 12.8
1651+
1652+-}
1653+modular : Float -> Float -> Int -> Float
1654+modular normal ratio rescale =
1655+ if rescale == 0 then
1656+ normal
1657+
1658+ else if rescale < 0 then
1659+ normal * ratio ^ toFloat rescale
1660+
1661+ else
1662+ normal * ratio ^ (toFloat rescale - 1)
1663+
1664+
1665+{-| -}
1666+mouseOver : List Decoration -> Attribute msg
1667+mouseOver decs =
1668+ Internal.StyleClass Flag.hover <|
1669+ Internal.PseudoSelector Internal.Hover
1670+ (Internal.unwrapDecorations decs)
1671+
1672+
1673+{-| -}
1674+mouseDown : List Decoration -> Attribute msg
1675+mouseDown decs =
1676+ Internal.StyleClass Flag.active <|
1677+ Internal.PseudoSelector Internal.Active
1678+ (Internal.unwrapDecorations decs)
1679+
1680+
1681+{-| -}
1682+focused : List Decoration -> Attribute msg
1683+focused decs =
1684+ Internal.StyleClass Flag.focus <|
1685+ Internal.PseudoSelector Internal.Focus
1686+ (Internal.unwrapDecorations decs)
deps/elm-ui/src/Element/Background.elmnew file+226
@@ -0,0 +1,226 @@
1+module Element.Background exposing
2+ ( color, gradient
3+ , image, uncropped, tiled, tiledX, tiledY
4+ )
5+
6+{-|
7+
8+@docs color, gradient
9+
10+
11+# Images
12+
13+@docs image, uncropped, tiled, tiledX, tiledY
14+
15+**Note** if you want more control over a background image than is provided here, you should try just using a normal `Element.image` with something like `Element.behindContent`.
16+
17+-}
18+
19+import Element exposing (Attr, Attribute, Color)
20+import Internal.Flag as Flag
21+import Internal.Model as Internal
22+import VirtualDom
23+
24+
25+{-| -}
26+color : Color -> Attr decorative msg
27+color clr =
28+ Internal.StyleClass Flag.bgColor (Internal.Colored ("bg-" ++ Internal.formatColorClass clr) "background-color" clr)
29+
30+
31+{-| Resize the image to fit the containing element while maintaining proportions and cropping the overflow.
32+-}
33+image : String -> Attribute msg
34+image src =
35+ Internal.Attr (VirtualDom.style "background" ("url(\"" ++ src ++ "\") center / cover no-repeat"))
36+
37+
38+{-| A centered background image that keeps its natural proportions, but scales to fit the space.
39+-}
40+uncropped : String -> Attribute msg
41+uncropped src =
42+ Internal.Attr (VirtualDom.style "background" ("url(\"" ++ src ++ "\") center / contain no-repeat"))
43+
44+
45+{-| Tile an image in the x and y axes.
46+-}
47+tiled : String -> Attribute msg
48+tiled src =
49+ Internal.Attr (VirtualDom.style "background" ("url(\"" ++ src ++ "\") repeat"))
50+
51+
52+{-| Tile an image in the x axis.
53+-}
54+tiledX : String -> Attribute msg
55+tiledX src =
56+ Internal.Attr (VirtualDom.style "background" ("url(\"" ++ src ++ "\") repeat-x"))
57+
58+
59+{-| Tile an image in the y axis.
60+-}
61+tiledY : String -> Attribute msg
62+tiledY src =
63+ Internal.Attr (VirtualDom.style "background" ("url(\"" ++ src ++ "\") repeat-y"))
64+
65+
66+type Direction
67+ = ToUp
68+ | ToDown
69+ | ToRight
70+ | ToTopRight
71+ | ToBottomRight
72+ | ToLeft
73+ | ToTopLeft
74+ | ToBottomLeft
75+ | ToAngle Float
76+
77+
78+type Step
79+ = ColorStep Color
80+ | PercentStep Float Color
81+ | PxStep Int Color
82+
83+
84+{-| -}
85+step : Color -> Step
86+step =
87+ ColorStep
88+
89+
90+{-| -}
91+percent : Float -> Color -> Step
92+percent =
93+ PercentStep
94+
95+
96+{-| -}
97+px : Int -> Color -> Step
98+px =
99+ PxStep
100+
101+
102+{-| A linear gradient.
103+
104+First you need to specify what direction the gradient is going by providing an angle in radians. `0` is up and `pi` is down.
105+
106+The colors will be evenly spaced.
107+
108+-}
109+gradient :
110+ { angle : Float
111+ , steps : List Color
112+ }
113+ -> Attr decorative msg
114+gradient { angle, steps } =
115+ case steps of
116+ [] ->
117+ Internal.NoAttribute
118+
119+ clr :: [] ->
120+ Internal.StyleClass Flag.bgColor
121+ (Internal.Colored ("bg-" ++ Internal.formatColorClass clr) "background-color" clr)
122+
123+ _ ->
124+ Internal.StyleClass Flag.bgGradient <|
125+ Internal.Single ("bg-grad-" ++ (String.join "-" <| Internal.floatClass angle :: List.map Internal.formatColorClass steps))
126+ "background-image"
127+ ("linear-gradient(" ++ (String.join ", " <| (String.fromFloat angle ++ "rad") :: List.map Internal.formatColor steps) ++ ")")
128+
129+
130+
131+-- {-| -}
132+-- gradientWith : { direction : Direction, steps : List Step } -> Attribute msg
133+-- gradientWith { direction, steps } =
134+-- StyleClass <|
135+-- Single ("bg-gradient-" ++ (String.join "-" <| renderDirectionClass direction :: List.map renderStepClass steps))
136+-- "background"
137+-- ("linear-gradient(" ++ (String.join ", " <| renderDirection direction :: List.map renderStep steps) ++ ")")
138+-- {-| -}
139+-- renderStep : Step -> String
140+-- renderStep step =
141+-- case step of
142+-- ColorStep color ->
143+-- formatColor color
144+-- PercentStep percent color ->
145+-- formatColor color ++ " " ++ toString percent ++ "%"
146+-- PxStep px color ->
147+-- formatColor color ++ " " ++ toString px ++ "px"
148+-- {-| -}
149+-- renderStepClass : Step -> String
150+-- renderStepClass step =
151+-- case step of
152+-- ColorStep color ->
153+-- formatColorClass color
154+-- PercentStep percent color ->
155+-- formatColorClass color ++ "-" ++ floatClass percent ++ "p"
156+-- PxStep px color ->
157+-- formatColorClass color ++ "-" ++ toString px ++ "px"
158+-- toUp : Direction
159+-- toUp =
160+-- ToUp
161+-- toDown : Direction
162+-- toDown =
163+-- ToDown
164+-- toRight : Direction
165+-- toRight =
166+-- ToRight
167+-- toTopRight : Direction
168+-- toTopRight =
169+-- ToTopRight
170+-- toBottomRight : Direction
171+-- toBottomRight =
172+-- ToBottomRight
173+-- toLeft : Direction
174+-- toLeft =
175+-- ToLeft
176+-- toTopLeft : Direction
177+-- toTopLeft =
178+-- ToTopLeft
179+-- toBottomLeft : Direction
180+-- toBottomLeft =
181+-- ToBottomLeft
182+-- angle : Float -> Direction
183+-- angle rad =
184+-- ToAngle rad
185+-- renderDirection : Direction -> String
186+-- renderDirection dir =
187+-- case dir of
188+-- ToUp ->
189+-- "to top"
190+-- ToDown ->
191+-- "to bottom"
192+-- ToRight ->
193+-- "to right"
194+-- ToTopRight ->
195+-- "to top right"
196+-- ToBottomRight ->
197+-- "to bottom right"
198+-- ToLeft ->
199+-- "to left"
200+-- ToTopLeft ->
201+-- "to top left"
202+-- ToBottomLeft ->
203+-- "to bottom left"
204+-- ToAngle angle ->
205+-- toString angle ++ "rad"
206+-- renderDirectionClass : Direction -> String
207+-- renderDirectionClass dir =
208+-- case dir of
209+-- ToUp ->
210+-- "to-top"
211+-- ToDown ->
212+-- "to-bottom"
213+-- ToRight ->
214+-- "to-right"
215+-- ToTopRight ->
216+-- "to-top-right"
217+-- ToBottomRight ->
218+-- "to-bottom-right"
219+-- ToLeft ->
220+-- "to-left"
221+-- ToTopLeft ->
222+-- "to-top-left"
223+-- ToBottomLeft ->
224+-- "to-bottom-left"
225+-- ToAngle angle ->
226+-- floatClass angle ++ "rad"
deps/elm-ui/src/Element/Border.elmnew file+281
@@ -0,0 +1,281 @@
1+module Element.Border exposing
2+ ( color
3+ , width, widthXY, widthEach
4+ , solid, dashed, dotted
5+ , rounded, roundEach
6+ , glow, innerGlow, shadow, innerShadow
7+ )
8+
9+{-|
10+
11+@docs color
12+
13+
14+## Border Widths
15+
16+@docs width, widthXY, widthEach
17+
18+
19+## Border Styles
20+
21+@docs solid, dashed, dotted
22+
23+
24+## Rounded Corners
25+
26+@docs rounded, roundEach
27+
28+
29+## Shadows
30+
31+@docs glow, innerGlow, shadow, innerShadow
32+
33+-}
34+
35+import Element exposing (Attr, Attribute, Color)
36+import Internal.Flag as Flag
37+import Internal.Model as Internal
38+import Internal.Style as Style exposing (classes)
39+
40+
41+{-| -}
42+color : Color -> Attr decorative msg
43+color clr =
44+ Internal.StyleClass
45+ Flag.borderColor
46+ (Internal.Colored
47+ ("bc-" ++ Internal.formatColorClass clr)
48+ "border-color"
49+ clr
50+ )
51+
52+
53+{-| -}
54+width : Int -> Attribute msg
55+width v =
56+ Internal.StyleClass
57+ Flag.borderWidth
58+ (Internal.BorderWidth
59+ ("b-" ++ String.fromInt v)
60+ v
61+ v
62+ v
63+ v
64+ )
65+
66+
67+{-| Set horizontal and vertical borders.
68+-}
69+widthXY : Int -> Int -> Attribute msg
70+widthXY x y =
71+ Internal.StyleClass
72+ Flag.borderWidth
73+ (Internal.BorderWidth
74+ ("b-"
75+ ++ String.fromInt x
76+ ++ "-"
77+ ++ String.fromInt y
78+ )
79+ y
80+ x
81+ y
82+ x
83+ )
84+
85+
86+{-| -}
87+widthEach :
88+ { bottom : Int
89+ , left : Int
90+ , right : Int
91+ , top : Int
92+ }
93+ -> Attribute msg
94+widthEach { bottom, top, left, right } =
95+ if top == bottom && left == right then
96+ if top == right then
97+ width top
98+
99+ else
100+ widthXY left top
101+
102+ else
103+ Internal.StyleClass Flag.borderWidth
104+ (Internal.BorderWidth
105+ ("b-"
106+ ++ String.fromInt top
107+ ++ "-"
108+ ++ String.fromInt right
109+ ++ "-"
110+ ++ String.fromInt bottom
111+ ++ "-"
112+ ++ String.fromInt left
113+ )
114+ top
115+ right
116+ bottom
117+ left
118+ )
119+
120+
121+
122+-- {-| No Borders
123+-- -}
124+-- none : Attribute msg
125+-- none =
126+-- Class "border" "border-none"
127+
128+
129+{-| -}
130+solid : Attribute msg
131+solid =
132+ Internal.Class Flag.borderStyle classes.borderSolid
133+
134+
135+{-| -}
136+dashed : Attribute msg
137+dashed =
138+ Internal.Class Flag.borderStyle classes.borderDashed
139+
140+
141+{-| -}
142+dotted : Attribute msg
143+dotted =
144+ Internal.Class Flag.borderStyle classes.borderDotted
145+
146+
147+{-| Round all corners.
148+-}
149+rounded : Int -> Attribute msg
150+rounded radius =
151+ Internal.StyleClass
152+ Flag.borderRound
153+ (Internal.Single
154+ ("br-" ++ String.fromInt radius)
155+ "border-radius"
156+ (String.fromInt radius ++ "px")
157+ )
158+
159+
160+{-| -}
161+roundEach :
162+ { topLeft : Int
163+ , topRight : Int
164+ , bottomLeft : Int
165+ , bottomRight : Int
166+ }
167+ -> Attribute msg
168+roundEach { topLeft, topRight, bottomLeft, bottomRight } =
169+ Internal.StyleClass Flag.borderRound
170+ (Internal.Single
171+ ("br-"
172+ ++ String.fromInt topLeft
173+ ++ "-"
174+ ++ String.fromInt topRight
175+ ++ String.fromInt bottomLeft
176+ ++ "-"
177+ ++ String.fromInt bottomRight
178+ )
179+ "border-radius"
180+ (String.fromInt topLeft
181+ ++ "px "
182+ ++ String.fromInt topRight
183+ ++ "px "
184+ ++ String.fromInt bottomRight
185+ ++ "px "
186+ ++ String.fromInt bottomLeft
187+ ++ "px"
188+ )
189+ )
190+
191+
192+{-| A simple glow by specifying the color and size.
193+-}
194+glow : Color -> Float -> Attr decorative msg
195+glow clr size =
196+ shadow
197+ { offset = ( 0, 0 )
198+ , size = size
199+ , blur = size * 2
200+ , color = clr
201+ }
202+
203+
204+{-| -}
205+innerGlow : Color -> Float -> Attr decorative msg
206+innerGlow clr size =
207+ innerShadow
208+ { offset = ( 0, 0 )
209+ , size = size
210+ , blur = size * 2
211+ , color = clr
212+ }
213+
214+
215+{-| -}
216+shadow :
217+ { offset : ( Float, Float )
218+ , size : Float
219+ , blur : Float
220+ , color : Color
221+ }
222+ -> Attr decorative msg
223+shadow almostShade =
224+ let
225+ shade =
226+ { inset = False
227+ , offset = almostShade.offset
228+ , size = almostShade.size
229+ , blur = almostShade.blur
230+ , color = almostShade.color
231+ }
232+ in
233+ Internal.StyleClass Flag.shadows <|
234+ Internal.Single
235+ (Internal.boxShadowClass shade)
236+ "box-shadow"
237+ (Internal.formatBoxShadow shade)
238+
239+
240+{-| -}
241+innerShadow :
242+ { offset : ( Float, Float )
243+ , size : Float
244+ , blur : Float
245+ , color : Color
246+ }
247+ -> Attr decorative msg
248+innerShadow almostShade =
249+ let
250+ shade =
251+ { inset = True
252+ , offset = almostShade.offset
253+ , size = almostShade.size
254+ , blur = almostShade.blur
255+ , color = almostShade.color
256+ }
257+ in
258+ Internal.StyleClass Flag.shadows <|
259+ Internal.Single
260+ (Internal.boxShadowClass shade)
261+ "box-shadow"
262+ (Internal.formatBoxShadow shade)
263+
264+
265+
266+-- {-| -}
267+-- shadow :
268+-- { offset : ( Float, Float )
269+-- , blur : Float
270+-- , size : Float
271+-- , color : Color
272+-- }
273+-- -> Attr decorative msg
274+-- shadow shade =
275+-- Internal.BoxShadow
276+-- { inset = False
277+-- , offset = shade.offset
278+-- , size = shade.size
279+-- , blur = shade.blur
280+-- , color = shade.color
281+-- }
deps/elm-ui/src/Element/Events.elmnew file+265
@@ -0,0 +1,265 @@
1+module Element.Events exposing
2+ ( onClick, onDoubleClick, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave, onMouseMove
3+ , onFocus, onLoseFocus
4+ -- , onClickCoords
5+ -- , onClickPageCoords
6+ -- , onClickScreenCoords
7+ -- , onMouseCoords
8+ -- , onMousePageCoords
9+ -- , onMouseScreenCoords
10+ )
11+
12+{-|
13+
14+
15+## Mouse Events
16+
17+@docs onClick, onDoubleClick, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave, onMouseMove
18+
19+
20+## Focus Events
21+
22+@docs onFocus, onLoseFocus
23+
24+-}
25+
26+import Element exposing (Attribute)
27+import Html.Events
28+import Internal.Model as Internal
29+import Json.Decode as Json
30+import VirtualDom
31+
32+
33+
34+-- MOUSE EVENTS
35+
36+
37+{-| -}
38+onMouseDown : msg -> Attribute msg
39+onMouseDown =
40+ Internal.Attr << Html.Events.onMouseDown
41+
42+
43+{-| -}
44+onMouseUp : msg -> Attribute msg
45+onMouseUp =
46+ Internal.Attr << Html.Events.onMouseUp
47+
48+
49+{-| -}
50+onClick : msg -> Attribute msg
51+onClick =
52+ Internal.Attr << Html.Events.onClick
53+
54+
55+{-| -}
56+onDoubleClick : msg -> Attribute msg
57+onDoubleClick =
58+ Internal.Attr << Html.Events.onDoubleClick
59+
60+
61+{-| -}
62+onMouseEnter : msg -> Attribute msg
63+onMouseEnter =
64+ Internal.Attr << Html.Events.onMouseEnter
65+
66+
67+{-| -}
68+onMouseLeave : msg -> Attribute msg
69+onMouseLeave =
70+ Internal.Attr << Html.Events.onMouseLeave
71+
72+
73+{-| -}
74+onMouseMove : msg -> Attribute msg
75+onMouseMove msg =
76+ on "mousemove" (Json.succeed msg)
77+
78+
79+
80+-- onClickWith
81+-- { button = primary
82+-- , send = localCoords Button
83+-- }
84+-- type alias Click =
85+-- { button : Button
86+-- , send : Track
87+-- }
88+-- type Button = Primary | Secondary
89+-- type Track
90+-- = ElementCoords
91+-- | PageCoords
92+-- | ScreenCoords
93+-- |
94+
95+
96+{-| -}
97+onClickCoords : (Coords -> msg) -> Attribute msg
98+onClickCoords msg =
99+ on "click" (Json.map msg localCoords)
100+
101+
102+{-| -}
103+onClickScreenCoords : (Coords -> msg) -> Attribute msg
104+onClickScreenCoords msg =
105+ on "click" (Json.map msg screenCoords)
106+
107+
108+{-| -}
109+onClickPageCoords : (Coords -> msg) -> Attribute msg
110+onClickPageCoords msg =
111+ on "click" (Json.map msg pageCoords)
112+
113+
114+{-| -}
115+onMouseCoords : (Coords -> msg) -> Attribute msg
116+onMouseCoords msg =
117+ on "mousemove" (Json.map msg localCoords)
118+
119+
120+{-| -}
121+onMouseScreenCoords : (Coords -> msg) -> Attribute msg
122+onMouseScreenCoords msg =
123+ on "mousemove" (Json.map msg screenCoords)
124+
125+
126+{-| -}
127+onMousePageCoords : (Coords -> msg) -> Attribute msg
128+onMousePageCoords msg =
129+ on "mousemove" (Json.map msg pageCoords)
130+
131+
132+type alias Coords =
133+ { x : Int
134+ , y : Int
135+ }
136+
137+
138+screenCoords : Json.Decoder Coords
139+screenCoords =
140+ Json.map2 Coords
141+ (Json.field "screenX" Json.int)
142+ (Json.field "screenY" Json.int)
143+
144+
145+{-| -}
146+localCoords : Json.Decoder Coords
147+localCoords =
148+ Json.map2 Coords
149+ (Json.field "offsetX" Json.int)
150+ (Json.field "offsetY" Json.int)
151+
152+
153+pageCoords : Json.Decoder Coords
154+pageCoords =
155+ Json.map2 Coords
156+ (Json.field "pageX" Json.int)
157+ (Json.field "pageY" Json.int)
158+
159+
160+
161+-- FOCUS EVENTS
162+
163+
164+{-| -}
165+onLoseFocus : msg -> Attribute msg
166+onLoseFocus =
167+ Internal.Attr << Html.Events.onBlur
168+
169+
170+{-| -}
171+onFocus : msg -> Attribute msg
172+onFocus =
173+ Internal.Attr << Html.Events.onFocus
174+
175+
176+
177+-- CUSTOM EVENTS
178+
179+
180+{-| Create a custom event listener. Normally this will not be necessary, but
181+you have the power! Here is how `onClick` is defined for example:
182+
183+ import Json.Decode as Json
184+
185+ onClick : msg -> Attribute msg
186+ onClick message =
187+ on "click" (Json.succeed message)
188+
189+The first argument is the event name in the same format as with JavaScript's
190+[`addEventListener`][aEL] function.
191+The second argument is a JSON decoder. Read more about these [here][decoder].
192+When an event occurs, the decoder tries to turn the event object into an Elm
193+value. If successful, the value is routed to your `update` function. In the
194+case of `onClick` we always just succeed with the given `message`.
195+If this is confusing, work through the [Elm Architecture Tutorial][tutorial].
196+It really does help!
197+[aEL]: <https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener>
198+[decoder]: <http://package.elm-lang.org/packages/elm-lang/core/latest/Json-Decode>
199+[tutorial]: <https://github.com/evancz/elm-architecture-tutorial/>
200+
201+-}
202+on : String -> Json.Decoder msg -> Attribute msg
203+on event decode =
204+ Internal.Attr <| Html.Events.on event decode
205+
206+
207+
208+-- {-| Same as `on` but you can set a few options.
209+-- -}
210+-- onWithOptions : String -> Html.Events.Options -> Json.Decoder msg -> Attribute msg
211+-- onWithOptions event options decode =
212+-- Internal.Attr <| Html.Events.onWithOptions event options decode
213+-- COMMON DECODERS
214+
215+
216+{-| A `Json.Decoder` for grabbing `event.target.value`. We use this to define
217+`onInput` as follows:
218+
219+ import Json.Decode as Json
220+
221+ onInput : (String -> msg) -> Attribute msg
222+ onInput tagger =
223+ on "input" (Json.map tagger targetValue)
224+
225+You probably will never need this, but hopefully it gives some insights into
226+how to make custom event handlers.
227+
228+-}
229+targetValue : Json.Decoder String
230+targetValue =
231+ Json.at [ "target", "value" ] Json.string
232+
233+
234+{-| A `Json.Decoder` for grabbing `event.target.checked`. We use this to define
235+`onCheck` as follows:
236+
237+ import Json.Decode as Json
238+
239+ onCheck : (Bool -> msg) -> Attribute msg
240+ onCheck tagger =
241+ on "input" (Json.map tagger targetChecked)
242+
243+-}
244+targetChecked : Json.Decoder Bool
245+targetChecked =
246+ Json.at [ "target", "checked" ] Json.bool
247+
248+
249+{-| A `Json.Decoder` for grabbing `event.keyCode`. This helps you define
250+keyboard listeners like this:
251+
252+ import Json.Decode as Json
253+
254+ onKeyUp : (Int -> msg) -> Attribute msg
255+ onKeyUp tagger =
256+ on "keyup" (Json.map tagger keyCode)
257+
258+**Note:** It looks like the spec is moving away from `event.keyCode` and
259+towards `event.key`. Once this is supported in more browsers, we may add
260+helpers here for `onKeyUp`, `onKeyDown`, `onKeyPress`, etc.
261+
262+-}
263+keyCode : Json.Decoder Int
264+keyCode =
265+ Json.field "keyCode" Json.int
deps/elm-ui/src/Element/Font.elmnew file+525
@@ -0,0 +1,525 @@
1+module Element.Font exposing
2+ ( color, size
3+ , family, Font, typeface, serif, sansSerif, monospace
4+ , external
5+ , alignLeft, alignRight, center, justify, letterSpacing, wordSpacing
6+ , underline, strike, italic, unitalicized
7+ , heavy, extraBold, bold, semiBold, medium, regular, light, extraLight, hairline
8+ , Variant, variant, variantList, smallCaps, slashedZero, ligatures, ordinal, tabularNumbers, stackedFractions, diagonalFractions, swash, feature, indexed
9+ , glow, shadow
10+ )
11+
12+{-|
13+
14+ import Element
15+ import Element.Font as Font
16+
17+ view =
18+ Element.el
19+ [ Font.color (Element.rgb 0 0 1)
20+ , Font.size 18
21+ , Font.family
22+ [ Font.typeface "Open Sans"
23+ , Font.sansSerif
24+ ]
25+ ]
26+ (Element.text "Woohoo, I'm stylish text")
27+
28+**Note:** `Font.color`, `Font.size`, and `Font.family` are inherited, meaning you can set them at the top of your view and all subsequent nodes will have that value.
29+
30+**Other Note:** If you're looking for something like `line-height`, it's handled by `Element.spacing` on a `paragraph`.
31+
32+@docs color, size
33+
34+
35+## Typefaces
36+
37+@docs family, Font, typeface, serif, sansSerif, monospace
38+
39+@docs external
40+
41+
42+## Alignment and Spacing
43+
44+@docs alignLeft, alignRight, center, justify, letterSpacing, wordSpacing
45+
46+
47+## Font Styles
48+
49+@docs underline, strike, italic, unitalicized
50+
51+
52+## Font Weight
53+
54+@docs heavy, extraBold, bold, semiBold, medium, regular, light, extraLight, hairline
55+
56+
57+## Variants
58+
59+@docs Variant, variant, variantList, smallCaps, slashedZero, ligatures, ordinal, tabularNumbers, stackedFractions, diagonalFractions, swash, feature, indexed
60+
61+
62+## Shadows
63+
64+@docs glow, shadow
65+
66+-}
67+
68+import Element exposing (Attr, Attribute, Color)
69+import Internal.Flag as Flag
70+import Internal.Model as Internal
71+import Internal.Style exposing (classes)
72+
73+
74+{-| -}
75+type alias Font =
76+ Internal.Font
77+
78+
79+{-| -}
80+color : Color -> Attr decorative msg
81+color fontColor =
82+ Internal.StyleClass
83+ Flag.fontColor
84+ (Internal.Colored
85+ ("fc-" ++ Internal.formatColorClass fontColor)
86+ "color"
87+ fontColor
88+ )
89+
90+
91+{-|
92+
93+ import Element
94+ import Element.Font as Font
95+
96+ myElement =
97+ Element.el
98+ [ Font.family
99+ [ Font.typeface "Helvetica"
100+ , Font.sansSerif
101+ ]
102+ ]
103+ (text "")
104+
105+-}
106+family : List Font -> Attribute msg
107+family families =
108+ Internal.StyleClass
109+ Flag.fontFamily
110+ (Internal.FontFamily
111+ (List.foldl Internal.renderFontClassName "ff-" families)
112+ families
113+ )
114+
115+
116+{-| -}
117+serif : Font
118+serif =
119+ Internal.Serif
120+
121+
122+{-| -}
123+sansSerif : Font
124+sansSerif =
125+ Internal.SansSerif
126+
127+
128+{-| -}
129+monospace : Font
130+monospace =
131+ Internal.Monospace
132+
133+
134+{-| -}
135+typeface : String -> Font
136+typeface =
137+ Internal.Typeface
138+
139+
140+{-| -}
141+type alias Adjustment =
142+ { capital : Float
143+ , lowercase : Float
144+ , baseline : Float
145+ , descender : Float
146+ }
147+
148+
149+{-| -}
150+with :
151+ { name : String
152+ , adjustment : Maybe Adjustment
153+ , variants : List Variant
154+ }
155+ -> Font
156+with =
157+ Internal.FontWith
158+
159+
160+{-| -}
161+sizeByCapital : Attribute msg
162+sizeByCapital =
163+ Internal.htmlClass classes.sizeByCapital
164+
165+
166+{-| -}
167+full : Attribute msg
168+full =
169+ Internal.htmlClass classes.fullSize
170+
171+
172+{-| **Note** it's likely that `Font.external` will cause a flash on your page on loading.
173+
174+To bypass this, import your fonts using a separate stylesheet and just use `Font.typeface`.
175+
176+It's likely that `Font.external` will be removed or redesigned in the future to avoid the flashing.
177+
178+`Font.external` can be used to import font files. Let's say you found a neat font on <http://fonts.google.com>:
179+
180+ import Element
181+ import Element.Font as Font
182+
183+ view =
184+ Element.el
185+ [ Font.family
186+ [ Font.external
187+ { name = "Roboto"
188+ , url = "https://fonts.googleapis.com/css?family=Roboto"
189+ }
190+ , Font.sansSerif
191+ ]
192+ ]
193+ (Element.text "Woohoo, I'm stylish text")
194+
195+-}
196+external : { url : String, name : String } -> Font
197+external { url, name } =
198+ Internal.ImportFont name url
199+
200+
201+{-| Font sizes are always given as `px`.
202+-}
203+size : Int -> Attr decorative msg
204+size i =
205+ Internal.StyleClass Flag.fontSize (Internal.FontSize i)
206+
207+
208+{-| In `px`.
209+-}
210+letterSpacing : Float -> Attribute msg
211+letterSpacing offset =
212+ Internal.StyleClass Flag.letterSpacing <|
213+ Internal.Single
214+ ("ls-" ++ Internal.floatClass offset)
215+ "letter-spacing"
216+ (String.fromFloat offset ++ "px")
217+
218+
219+{-| In `px`.
220+-}
221+wordSpacing : Float -> Attribute msg
222+wordSpacing offset =
223+ Internal.StyleClass Flag.wordSpacing <|
224+ Internal.Single ("ws-" ++ Internal.floatClass offset) "word-spacing" (String.fromFloat offset ++ "px")
225+
226+
227+{-| Align the font to the left.
228+-}
229+alignLeft : Attribute msg
230+alignLeft =
231+ Internal.Class Flag.fontAlignment classes.textLeft
232+
233+
234+{-| Align the font to the right.
235+-}
236+alignRight : Attribute msg
237+alignRight =
238+ Internal.Class Flag.fontAlignment classes.textRight
239+
240+
241+{-| Center align the font.
242+-}
243+center : Attribute msg
244+center =
245+ Internal.Class Flag.fontAlignment classes.textCenter
246+
247+
248+{-| -}
249+justify : Attribute msg
250+justify =
251+ Internal.Class Flag.fontAlignment classes.textJustify
252+
253+
254+
255+-- {-| -}
256+-- justifyAll : Attribute msg
257+-- justifyAll =
258+-- Internal.class classesTextJustifyAll
259+
260+
261+{-| -}
262+underline : Attribute msg
263+underline =
264+ Internal.htmlClass classes.underline
265+
266+
267+{-| -}
268+strike : Attribute msg
269+strike =
270+ Internal.htmlClass classes.strike
271+
272+
273+{-| -}
274+italic : Attribute msg
275+italic =
276+ Internal.htmlClass classes.italic
277+
278+
279+{-| -}
280+bold : Attribute msg
281+bold =
282+ Internal.Class Flag.fontWeight classes.bold
283+
284+
285+{-| -}
286+light : Attribute msg
287+light =
288+ Internal.Class Flag.fontWeight classes.textLight
289+
290+
291+{-| -}
292+hairline : Attribute msg
293+hairline =
294+ Internal.Class Flag.fontWeight classes.textThin
295+
296+
297+{-| -}
298+extraLight : Attribute msg
299+extraLight =
300+ Internal.Class Flag.fontWeight classes.textExtraLight
301+
302+
303+{-| -}
304+regular : Attribute msg
305+regular =
306+ Internal.Class Flag.fontWeight classes.textNormalWeight
307+
308+
309+{-| -}
310+semiBold : Attribute msg
311+semiBold =
312+ Internal.Class Flag.fontWeight classes.textSemiBold
313+
314+
315+{-| -}
316+medium : Attribute msg
317+medium =
318+ Internal.Class Flag.fontWeight classes.textMedium
319+
320+
321+{-| -}
322+extraBold : Attribute msg
323+extraBold =
324+ Internal.Class Flag.fontWeight classes.textExtraBold
325+
326+
327+{-| -}
328+heavy : Attribute msg
329+heavy =
330+ Internal.Class Flag.fontWeight classes.textHeavy
331+
332+
333+{-| This will reset bold and italic.
334+-}
335+unitalicized : Attribute msg
336+unitalicized =
337+ Internal.htmlClass classes.textUnitalicized
338+
339+
340+{-| -}
341+shadow :
342+ { offset : ( Float, Float )
343+ , blur : Float
344+ , color : Color
345+ }
346+ -> Attr decorative msg
347+shadow shade =
348+ Internal.StyleClass Flag.txtShadows <|
349+ Internal.Single (Internal.textShadowClass shade) "text-shadow" (Internal.formatTextShadow shade)
350+
351+
352+{-| A glow is just a simplified shadow.
353+-}
354+glow : Color -> Float -> Attr decorative msg
355+glow clr i =
356+ let
357+ shade =
358+ { offset = ( 0, 0 )
359+ , blur = i * 2
360+ , color = clr
361+ }
362+ in
363+ Internal.StyleClass Flag.txtShadows <|
364+ Internal.Single (Internal.textShadowClass shade) "text-shadow" (Internal.formatTextShadow shade)
365+
366+
367+
368+{- Variants -}
369+
370+
371+{-| -}
372+type alias Variant =
373+ Internal.Variant
374+
375+
376+{-| You can use this to set a single variant on an element itself such as:
377+
378+ el
379+ [ Font.variant Font.smallCaps
380+ ]
381+ (text "rendered with smallCaps")
382+
383+**Note** These will **not** stack. If you want multiple variants, you should use `Font.variantList`.
384+
385+-}
386+variant : Variant -> Attribute msg
387+variant var =
388+ case var of
389+ Internal.VariantActive name ->
390+ Internal.Class Flag.fontVariant ("v-" ++ name)
391+
392+ Internal.VariantOff name ->
393+ Internal.Class Flag.fontVariant ("v-" ++ name ++ "-off")
394+
395+ Internal.VariantIndexed name index ->
396+ Internal.StyleClass Flag.fontVariant <|
397+ Internal.Single ("v-" ++ name ++ "-" ++ String.fromInt index)
398+ "font-feature-settings"
399+ ("\"" ++ name ++ "\" " ++ String.fromInt index)
400+
401+
402+isSmallCaps x =
403+ case x of
404+ Internal.VariantActive feat ->
405+ feat == "smcp"
406+
407+ _ ->
408+ False
409+
410+
411+{-| -}
412+variantList : List Variant -> Attribute msg
413+variantList vars =
414+ let
415+ features =
416+ vars
417+ |> List.map Internal.renderVariant
418+
419+ hasSmallCaps =
420+ List.any isSmallCaps vars
421+
422+ name =
423+ if hasSmallCaps then
424+ vars
425+ |> List.map Internal.variantName
426+ |> String.join "-"
427+ |> (\x -> x ++ "-sc")
428+
429+ else
430+ vars
431+ |> List.map Internal.variantName
432+ |> String.join "-"
433+
434+ featureString =
435+ String.join ", " features
436+ in
437+ Internal.StyleClass Flag.fontVariant <|
438+ Internal.Style ("v-" ++ name)
439+ [ Internal.Property "font-feature-settings" featureString
440+ , Internal.Property "font-variant"
441+ (if hasSmallCaps then
442+ "small-caps"
443+
444+ else
445+ "normal"
446+ )
447+ ]
448+
449+
450+{-| [Small caps](https://en.wikipedia.org/wiki/Small_caps) are rendered using uppercase glyphs, but at the size of lowercase glyphs.
451+-}
452+smallCaps : Variant
453+smallCaps =
454+ Internal.VariantActive "smcp"
455+
456+
457+{-| Add a slash when rendering `0`
458+-}
459+slashedZero : Variant
460+slashedZero =
461+ Internal.VariantActive "zero"
462+
463+
464+{-| -}
465+ligatures : Variant
466+ligatures =
467+ Internal.VariantActive "liga"
468+
469+
470+{-| Oridinal markers like `1st` and `2nd` will receive special glyphs.
471+-}
472+ordinal : Variant
473+ordinal =
474+ Internal.VariantActive "ordn"
475+
476+
477+{-| Number figures will each take up the same space, allowing them to be easily aligned, such as in tables.
478+-}
479+tabularNumbers : Variant
480+tabularNumbers =
481+ Internal.VariantActive "tnum"
482+
483+
484+{-| Render fractions with the numerator stacked on top of the denominator.
485+-}
486+stackedFractions : Variant
487+stackedFractions =
488+ Internal.VariantActive "afrc"
489+
490+
491+{-| Render fractions
492+-}
493+diagonalFractions : Variant
494+diagonalFractions =
495+ Internal.VariantActive "frac"
496+
497+
498+{-| -}
499+swash : Int -> Variant
500+swash =
501+ Internal.VariantIndexed "swsh"
502+
503+
504+{-| Set a feature by name and whether it should be on or off.
505+
506+Feature names are four-letter names as defined in the [OpenType specification](https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist).
507+
508+-}
509+feature : String -> Bool -> Variant
510+feature name on =
511+ if on then
512+ Internal.VariantIndexed name 1
513+
514+ else
515+ Internal.VariantIndexed name 0
516+
517+
518+{-| A font variant might have multiple versions within the font.
519+
520+In these cases we need to specify the index of the version we want.
521+
522+-}
523+indexed : String -> Int -> Variant
524+indexed name on =
525+ Internal.VariantIndexed name on
deps/elm-ui/src/Element/Input.elmnew file+2265
@@ -0,0 +1,2265 @@
1+module Element.Input exposing
2+ ( focusedOnLoad
3+ , button
4+ , checkbox, defaultCheckbox
5+ , text, multiline
6+ , Placeholder, placeholder
7+ , username, newPassword, currentPassword, email, search, spellChecked
8+ , slider, Thumb, thumb, defaultThumb
9+ , radio, radioRow, Option, option, optionWith, OptionState(..)
10+ , Label, labelAbove, labelBelow, labelLeft, labelRight, labelHidden
11+ )
12+
13+{-| Input elements have a lot of constraints!
14+
15+We want all of our input elements to:
16+
17+ - _Always be accessible_
18+ - _Behave intuitively_
19+ - _Be completely restyleable_
20+
21+While these three goals may seem pretty obvious, Html and CSS have made it surprisingly difficult to achieve!
22+
23+And incredibly difficult for developers to remember all the tricks necessary to make things work. If you've every tried to make a `<textarea>` be the height of it's content or restyle a radio button while maintaining accessibility, you may be familiar.
24+
25+This module is intended to be accessible by default. You shouldn't have to wade through docs, articles, and books to find out [exactly how accessible your html actually is](https://www.powermapper.com/tests/screen-readers/aria/index.html).
26+
27+
28+# Focus Styling
29+
30+All Elements can be styled on focus by using [`Element.focusStyle`](Element#focusStyle) to set a global focus style or [`Element.focused`](Element#focused) to set a focus style individually for an element.
31+
32+@docs focusedOnLoad
33+
34+
35+# Buttons
36+
37+@docs button
38+
39+
40+# Checkboxes
41+
42+A checkbox requires you to store a `Bool` in your model.
43+
44+This is also the first input element that has a [`required label`](#Label).
45+
46+ import Element exposing (text)
47+ import Element.Input as Input
48+
49+ type Msg
50+ = GuacamoleChecked Bool
51+
52+ view model =
53+ Input.checkbox []
54+ { onChange = GuacamoleChecked
55+ , icon = Input.defaultCheckbox
56+ , checked = model.guacamole
57+ , label =
58+ Input.labelRight []
59+ (text "Do you want Guacamole?")
60+ }
61+
62+@docs checkbox, defaultCheckbox
63+
64+
65+# Text
66+
67+@docs text, multiline
68+
69+@docs Placeholder, placeholder
70+
71+
72+## Text with autofill
73+
74+If we want to play nicely with a browser's ability to autofill a form, we need to be able to give it a hint about what we're expecting.
75+
76+The following inputs are very similar to `Input.text`, but they give the browser a hint to allow autofill to work correctly.
77+
78+@docs username, newPassword, currentPassword, email, search, spellChecked
79+
80+
81+# Sliders
82+
83+A slider is great for choosing between a range of numerical values.
84+
85+ - **thumb** - The icon that you click and drag to change the value.
86+ - **track** - The line behind the thumb denoting where you can slide to.
87+
88+@docs slider, Thumb, thumb, defaultThumb
89+
90+
91+# Radio Selection
92+
93+The fact that we still call this a radio selection is fascinating. I can't remember the last time I actually used an honest-to-goodness button on a radio. Chalk it up along with the floppy disk save icon or the word [Dashboard](https://en.wikipedia.org/wiki/Dashboard).
94+
95+Perhaps a better name would be `Input.chooseOne`, because this allows you to select one of a set of options!
96+
97+Nevertheless, here we are. Here's how you put one together
98+
99+ Input.radio
100+ [ padding 10
101+ , spacing 20
102+ ]
103+ { onChange = ChooseLunch
104+ , selected = Just model.lunch
105+ , label = Input.labelAbove [] (text "Lunch")
106+ , options =
107+ [ Input.option Burrito (text "Burrito")
108+ , Input.option Taco (text "Taco!")
109+ , Input.option Gyro (text "Gyro")
110+ ]
111+ }
112+
113+**Note** we're using `Input.option`, which will render the default radio icon you're probably used to. If you want compeltely custom styling, use `Input.optionWith`!
114+
115+@docs radio, radioRow, Option, option, optionWith, OptionState
116+
117+
118+# Labels
119+
120+Every input has a required `Label`.
121+
122+@docs Label, labelAbove, labelBelow, labelLeft, labelRight, labelHidden
123+
124+
125+# Form Elements
126+
127+You might be wondering where something like `<form>` is.
128+
129+What I've found is that most people who want `<form>` usually want it for the [implicit submission behavior](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#implicit-submission) or to be clearer, they want to do something when the `Enter` key is pressed.
130+
131+Instead of implicit submission behavior, [try making an `onEnter` event handler like in this Ellie Example](https://ellie-app.com/5X6jBKtxzdpa1). Then everything is explicit!
132+
133+And no one has to look up obtuse html documentation to understand the behavior of their code :).
134+
135+
136+# File Inputs
137+
138+Presently, 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.
139+
140+
141+# Disabling Inputs
142+
143+You also might be wondering how to disable an input.
144+
145+Disabled inputs can be a little problematic for user experience, and doubly so for accessibility. This is because it's now your priority to inform the user _why_ some field is disabled.
146+
147+If an input is truly disabled, meaning it's not focusable or doesn't send off a `Msg`, you actually lose your ability to help the user out! For those wary about accessibility [this is a big problem.](https://ux.stackexchange.com/questions/103239/should-disabled-elements-be-focusable-for-accessibility-purposes)
148+
149+Here are some alternatives to think about that don't involve explicitly disabling an input.
150+
151+**Disabled Buttons** - Change the `Msg` it fires, the text that is rendered, and optionally set a `Region.description` which will be available to screen readers.
152+
153+ import Element.Input as Input
154+ import Element.Region as Region
155+
156+ myButton ready =
157+ if ready then
158+ Input.button
159+ [ Background.color blue
160+ ]
161+ { onPress =
162+ Just SaveButtonPressed
163+ , label =
164+ text "Save blog post"
165+ }
166+
167+ else
168+ Input.button
169+ [ Background.color grey
170+ , Region.description
171+ "A publish date is required before saving a blogpost."
172+ ]
173+ { onPress =
174+ Just DisabledSaveButtonPressed
175+ , label =
176+ text "Save Blog "
177+ }
178+
179+Consider showing a hint if `DisabledSaveButtonPressed` is sent.
180+
181+For other inputs such as `Input.text`, consider simply rendering it in a normal `paragraph` or `el` if it's not editable.
182+
183+Alternatively, see if it's reasonable to _not_ display an input if you'd normally disable it. Is there an option where it's only visible when it's editable?
184+
185+-}
186+
187+import Element exposing (Attribute, Color, Element)
188+import Element.Background as Background
189+import Element.Border as Border
190+import Element.Events as Events
191+import Element.Font as Font
192+import Element.Region as Region
193+import Html
194+import Html.Attributes
195+import Html.Events
196+import Internal.Flag as Flag
197+import Internal.Model as Internal
198+import Internal.Style exposing (classes)
199+import Json.Decode as Json
200+
201+
202+{-| -}
203+type Placeholder msg
204+ = Placeholder (List (Attribute msg)) (Element msg)
205+
206+
207+white =
208+ Element.rgb 1 1 1
209+
210+
211+darkGrey =
212+ Element.rgb (186 / 255) (189 / 255) (182 / 255)
213+
214+
215+charcoal =
216+ Element.rgb
217+ (136 / 255)
218+ (138 / 255)
219+ (133 / 255)
220+
221+
222+{-| -}
223+placeholder : List (Attribute msg) -> Element msg -> Placeholder msg
224+placeholder =
225+ Placeholder
226+
227+
228+type LabelLocation
229+ = OnRight
230+ | OnLeft
231+ | Above
232+ | Below
233+
234+
235+{-| -}
236+type Label msg
237+ = Label LabelLocation (List (Attribute msg)) (Element msg)
238+ | HiddenLabel String
239+
240+
241+isStacked : Label msg -> Bool
242+isStacked label =
243+ case label of
244+ Label loc _ _ ->
245+ case loc of
246+ OnRight ->
247+ False
248+
249+ OnLeft ->
250+ False
251+
252+ Above ->
253+ True
254+
255+ Below ->
256+ True
257+
258+ HiddenLabel _ ->
259+ True
260+
261+
262+{-| -}
263+labelRight : List (Attribute msg) -> Element msg -> Label msg
264+labelRight =
265+ Label OnRight
266+
267+
268+{-| -}
269+labelLeft : List (Attribute msg) -> Element msg -> Label msg
270+labelLeft =
271+ Label OnLeft
272+
273+
274+{-| -}
275+labelAbove : List (Attribute msg) -> Element msg -> Label msg
276+labelAbove =
277+ Label Above
278+
279+
280+{-| -}
281+labelBelow : List (Attribute msg) -> Element msg -> Label msg
282+labelBelow =
283+ Label Below
284+
285+
286+{-| Sometimes you may need to have a label which is not visible, but is still accessible to screen readers.
287+
288+Seriously consider a visible label before using this.
289+
290+The situations where a hidden label makes sense:
291+
292+ - A searchbar with a `search` button right next to it.
293+ - A `table` of inputs where the header gives the label.
294+
295+Basically, a hidden label works when there are other contextual clues that sighted people can pick up on.
296+
297+-}
298+labelHidden : String -> Label msg
299+labelHidden =
300+ HiddenLabel
301+
302+
303+hiddenLabelAttribute label =
304+ case label of
305+ HiddenLabel textLabel ->
306+ Internal.Describe (Internal.Label textLabel)
307+
308+ Label _ _ _ ->
309+ Internal.NoAttribute
310+
311+
312+{-| A standard button.
313+
314+The `onPress` handler will be fired either `onClick` or when the element is focused and the `Enter` key has been pressed.
315+
316+ import Element exposing (rgb255, text)
317+ import Element.Background as Background
318+ import Element.Input as Input
319+
320+ blue =
321+ Element.rgb255 238 238 238
322+
323+ myButton =
324+ Input.button
325+ [ Background.color blue
326+ , Element.focused
327+ [ Background.color purple ]
328+ ]
329+ { onPress = Just ClickMsg
330+ , label = text "My Button"
331+ }
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+
335+-}
336+button :
337+ List (Attribute msg)
338+ ->
339+ { onPress : Maybe msg
340+ , label : Element msg
341+ }
342+ -> Element msg
343+button attrs { onPress, label } =
344+ Internal.element
345+ Internal.asEl
346+ -- We don't explicitly label this node as a button,
347+ -- because buttons fire a bunch of times when you hold down the enter key.
348+ -- We'd like to fire just once on the enter key, which means using keyup instead of keydown.
349+ -- Because we have no way to disable keydown, though our messages get doubled.
350+ Internal.div
351+ (Element.width Element.shrink
352+ :: Element.height Element.shrink
353+ :: Internal.htmlClass
354+ (classes.contentCenterX
355+ ++ " "
356+ ++ classes.contentCenterY
357+ ++ " "
358+ ++ classes.seButton
359+ ++ " "
360+ ++ classes.noTextSelection
361+ )
362+ :: Element.pointer
363+ :: focusDefault attrs
364+ :: Internal.Describe Internal.Button
365+ :: Internal.Attr (Html.Attributes.tabindex 0)
366+ :: (case onPress of
367+ Nothing ->
368+ Internal.Attr (Html.Attributes.disabled True) :: attrs
369+
370+ Just msg ->
371+ Events.onClick 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+ )
383+ :: attrs
384+ )
385+ )
386+ (Internal.Unkeyed [ label ])
387+
388+
389+focusDefault attrs =
390+ if List.any hasFocusStyle attrs then
391+ Internal.NoAttribute
392+
393+ else
394+ Internal.htmlClass "focusable"
395+
396+
397+hasFocusStyle attr =
398+ case attr of
399+ Internal.StyleClass _ (Internal.PseudoSelector Internal.Focus _) ->
400+ True
401+
402+ _ ->
403+ False
404+
405+
406+{-| -}
407+type alias Checkbox msg =
408+ { onChange : Maybe (Bool -> msg)
409+ , icon : Maybe (Element msg)
410+ , checked : Bool
411+ , label : Label msg
412+ }
413+
414+
415+{-|
416+
417+ - **onChange** - The `Msg` to send.
418+ - **icon** - The checkbox icon to show. This can be whatever you'd like, but `Input.defaultCheckbox` is included to get you started.
419+ - **checked** - The current checked state.
420+ - **label** - The [`Label`](#Label) for this checkbox
421+
422+-}
423+checkbox :
424+ List (Attribute msg)
425+ ->
426+ { onChange : Bool -> msg
427+ , icon : Bool -> Element msg
428+ , checked : Bool
429+ , label : Label msg
430+ }
431+ -> Element msg
432+checkbox attrs { label, icon, checked, onChange } =
433+ let
434+ attributes =
435+ [ if isHiddenLabel label then
436+ Internal.NoAttribute
437+
438+ else
439+ Element.spacing
440+ 6
441+ , Internal.Attr (Html.Events.onClick (onChange (not checked)))
442+ , Region.announce
443+ , onKeyLookup <|
444+ \code ->
445+ if code == enter then
446+ Just <| onChange (not checked)
447+
448+ else if code == space then
449+ Just <| onChange (not checked)
450+
451+ else
452+ Nothing
453+ , tabindex 0
454+ , Element.pointer
455+ , Element.alignLeft
456+ , Element.width Element.fill
457+ ]
458+ ++ attrs
459+ in
460+ applyLabel
461+ (Internal.Attr (Html.Attributes.attribute "role" "checkbox")
462+ :: Internal.Attr
463+ (Html.Attributes.attribute "aria-checked" <|
464+ if checked then
465+ "true"
466+
467+ else
468+ "false"
469+ )
470+ :: hiddenLabelAttribute label
471+ :: attributes
472+ )
473+ label
474+ (Internal.element
475+ Internal.asEl
476+ Internal.div
477+ [ Element.centerY
478+ , Element.height Element.fill
479+ , Element.width Element.shrink
480+ ]
481+ (Internal.Unkeyed
482+ [ icon checked
483+ ]
484+ )
485+ )
486+
487+
488+{-| -}
489+type Thumb
490+ = Thumb (List (Attribute Never))
491+
492+
493+{-| -}
494+thumb : List (Attribute Never) -> Thumb
495+thumb =
496+ Thumb
497+
498+
499+{-| -}
500+defaultThumb : Thumb
501+defaultThumb =
502+ Thumb
503+ [ Element.width (Element.px 16)
504+ , Element.height (Element.px 16)
505+ , Border.rounded 8
506+ , Border.width 1
507+ , Border.color (Element.rgb 0.5 0.5 0.5)
508+ , Background.color (Element.rgb 1 1 1)
509+ ]
510+
511+
512+{-| A slider input, good for capturing float values.
513+
514+ Input.slider
515+ [ Element.height (Element.px 30)
516+
517+ -- Here is where we're creating/styling the "track"
518+ , Element.behindContent
519+ (Element.el
520+ [ Element.width Element.fill
521+ , Element.height (Element.px 2)
522+ , Element.centerY
523+ , Background.color grey
524+ , Border.rounded 2
525+ ]
526+ Element.none
527+ )
528+ ]
529+ { onChange = AdjustValue
530+ , label =
531+ Input.labelAbove []
532+ (text "My Slider Value")
533+ , min = 0
534+ , max = 75
535+ , step = Nothing
536+ , value = model.sliderValue
537+ , thumb =
538+ Input.defaultThumb
539+ }
540+
541+`Element.behindContent` is used to render the track of the slider. Without it, no track would be rendered. The `thumb` is the icon that you can move around.
542+
543+The slider can be vertical or horizontal depending on the width/height of the slider.
544+
545+ - `height fill` and `width (px someWidth)` will cause the slider to be vertical.
546+ - `height (px someHeight)` and `width (px someWidth)` where `someHeight` > `someWidth` will also do it.
547+ - otherwise, the slider will be horizontal.
548+
549+**Note** If you want a slider for an `Int` value:
550+
551+ - set `step` to be `Just 1`, or some other whole value
552+ - `value = toFloat model.myInt`
553+ - And finally, round the value before making a message `onChange = round >> AdjustValue`
554+
555+-}
556+slider :
557+ List (Attribute msg)
558+ ->
559+ { onChange : Float -> msg
560+ , label : Label msg
561+ , min : Float
562+ , max : Float
563+ , value : Float
564+ , thumb : Thumb
565+ , step : Maybe Float
566+ }
567+ -> Element msg
568+slider attributes input =
569+ let
570+ (Thumb thumbAttributes) =
571+ input.thumb
572+
573+ width =
574+ Internal.getWidth thumbAttributes
575+
576+ height =
577+ Internal.getHeight thumbAttributes
578+
579+ vertical =
580+ case ( trackWidth, trackHeight ) of
581+ ( Nothing, Nothing ) ->
582+ False
583+
584+ ( Just (Internal.Px w), Just (Internal.Px h) ) ->
585+ h > w
586+
587+ ( Just (Internal.Px _), Just (Internal.Fill _) ) ->
588+ True
589+
590+ _ ->
591+ False
592+
593+ trackHeight =
594+ Internal.getHeight attributes
595+
596+ trackWidth =
597+ Internal.getWidth attributes
598+
599+ ( spacingX, spacingY ) =
600+ Internal.getSpacing attributes ( 5, 5 )
601+
602+ factor =
603+ (input.value - input.min)
604+ / (input.max - input.min)
605+
606+ {- Needed attributes
607+
608+ Thumb Attributes
609+ - Width/Height of thumb so that the input can shadow it.
610+
611+
612+ Attributes
613+
614+ OnParent ->
615+ Spacing
616+
617+
618+ On track ->
619+ Everything else
620+
621+
622+
623+
624+ The `<input>`
625+
626+
627+ -}
628+ className =
629+ "thmb-" ++ thumbWidthString ++ "-" ++ thumbHeightString
630+
631+ thumbWidthString =
632+ case width of
633+ Nothing ->
634+ "20px"
635+
636+ Just (Internal.Px px) ->
637+ String.fromInt px ++ "px"
638+
639+ _ ->
640+ "100%"
641+
642+ thumbHeightString =
643+ case height of
644+ Nothing ->
645+ "20px"
646+
647+ Just (Internal.Px px) ->
648+ String.fromInt px ++ "px"
649+
650+ _ ->
651+ "100%"
652+
653+ thumbShadowStyle =
654+ [ Internal.Property "width"
655+ thumbWidthString
656+ , Internal.Property "height"
657+ thumbHeightString
658+ ]
659+ in
660+ applyLabel
661+ [ if isHiddenLabel input.label then
662+ Internal.NoAttribute
663+
664+ else
665+ Element.spacingXY spacingX spacingY
666+ , Region.announce
667+ , Element.width
668+ (case trackWidth of
669+ Nothing ->
670+ Element.fill
671+
672+ Just (Internal.Px _) ->
673+ Element.shrink
674+
675+ Just x ->
676+ x
677+ )
678+ , Element.height
679+ (case trackHeight of
680+ Nothing ->
681+ Element.shrink
682+
683+ Just (Internal.Px _) ->
684+ Element.shrink
685+
686+ Just x ->
687+ x
688+ )
689+ ]
690+ input.label
691+ (Element.row
692+ [ Element.width
693+ (Maybe.withDefault Element.fill trackWidth)
694+ , Element.height
695+ (Maybe.withDefault (Element.px 20) trackHeight)
696+ ]
697+ [ Internal.element
698+ Internal.asEl
699+ (Internal.NodeName "input")
700+ [ hiddenLabelAttribute input.label
701+ , Internal.StyleClass Flag.active
702+ (Internal.Style
703+ ("input[type=\"range\"]." ++ className ++ "::-moz-range-thumb")
704+ thumbShadowStyle
705+ )
706+ , Internal.StyleClass Flag.hover
707+ (Internal.Style
708+ ("input[type=\"range\"]." ++ className ++ "::-webkit-slider-thumb")
709+ thumbShadowStyle
710+ )
711+ , Internal.StyleClass Flag.focus
712+ (Internal.Style
713+ ("input[type=\"range\"]." ++ className ++ "::-ms-thumb")
714+ thumbShadowStyle
715+ )
716+ , Internal.Attr (Html.Attributes.class (className ++ " ui-slide-bar focusable-parent"))
717+ , Internal.Attr
718+ (Html.Events.onInput
719+ (\str ->
720+ case String.toFloat str of
721+ Nothing ->
722+ -- This should never happen because the browser
723+ -- should always provide a Float.
724+ input.onChange 0
725+
726+ Just val ->
727+ input.onChange val
728+ )
729+ )
730+ , Internal.Attr <|
731+ Html.Attributes.type_ "range"
732+ , Internal.Attr <|
733+ Html.Attributes.step
734+ (case input.step of
735+ Nothing ->
736+ -- Note: If we set `any` here,
737+ -- Firefox makes a single press of the arrows keys equal to 1
738+ -- We could set the step manually to the effective range / 100
739+ -- String.fromFloat ((input.max - input.min) / 100)
740+ -- Which matches Chrome's default behavior
741+ -- HOWEVER, that means manually moving a slider with the mouse will snap to that interval.
742+ "any"
743+
744+ Just step ->
745+ String.fromFloat step
746+ )
747+ , Internal.Attr <|
748+ Html.Attributes.min (String.fromFloat input.min)
749+ , Internal.Attr <|
750+ Html.Attributes.max (String.fromFloat input.max)
751+ , Internal.Attr <|
752+ Html.Attributes.value (String.fromFloat input.value)
753+ , if vertical then
754+ Internal.Attr <|
755+ Html.Attributes.attribute "orient" "vertical"
756+
757+ else
758+ Internal.NoAttribute
759+ , Element.width <|
760+ if vertical then
761+ Maybe.withDefault (Element.px 20) trackHeight
762+
763+ else
764+ Maybe.withDefault Element.fill trackWidth
765+ , Element.height <|
766+ if vertical then
767+ Maybe.withDefault Element.fill trackWidth
768+
769+ else
770+ Maybe.withDefault (Element.px 20) trackHeight
771+ ]
772+ (Internal.Unkeyed [])
773+ , Element.el
774+ (Element.width
775+ (Maybe.withDefault Element.fill trackWidth)
776+ :: Element.height
777+ (Maybe.withDefault (Element.px 20) trackHeight)
778+ :: attributes
779+ -- This is after `attributes` because the thumb should be in front of everything.
780+ ++ [ Element.behindContent <|
781+ if vertical then
782+ viewVerticalThumb factor (Internal.htmlClass "focusable-thumb" :: thumbAttributes) trackWidth
783+
784+ else
785+ viewHorizontalThumb factor (Internal.htmlClass "focusable-thumb" :: thumbAttributes) trackHeight
786+ ]
787+ )
788+ Element.none
789+ ]
790+ )
791+
792+
793+viewHorizontalThumb factor thumbAttributes trackHeight =
794+ Element.row
795+ [ Element.width Element.fill
796+ , Element.height (Maybe.withDefault Element.fill trackHeight)
797+ , Element.centerY
798+ ]
799+ [ Element.el
800+ [ Element.width (Element.fillPortion (round <| factor * 10000))
801+ ]
802+ Element.none
803+ , Element.el
804+ (Element.centerY
805+ :: List.map (Internal.mapAttr Basics.never) thumbAttributes
806+ )
807+ Element.none
808+ , Element.el
809+ [ Element.width (Element.fillPortion (round <| (abs <| 1 - factor) * 10000))
810+ ]
811+ Element.none
812+ ]
813+
814+
815+viewVerticalThumb factor thumbAttributes trackWidth =
816+ Element.column
817+ [ Element.height Element.fill
818+ , Element.width (Maybe.withDefault Element.fill trackWidth)
819+ , Element.centerX
820+ ]
821+ [ Element.el
822+ [ Element.height (Element.fillPortion (round <| (abs <| 1 - factor) * 10000))
823+ ]
824+ Element.none
825+ , Element.el
826+ (Element.centerX
827+ :: List.map (Internal.mapAttr Basics.never) thumbAttributes
828+ )
829+ Element.none
830+ , Element.el
831+ [ Element.height (Element.fillPortion (round <| factor * 10000))
832+ ]
833+ Element.none
834+ ]
835+
836+
837+type alias TextInput =
838+ { type_ : TextKind
839+ , spellchecked : Bool
840+ , autofill : Maybe String
841+ }
842+
843+
844+type TextKind
845+ = TextInputNode String
846+ | TextArea
847+
848+
849+{-| -}
850+type alias Text msg =
851+ { onChange : String -> msg
852+ , text : String
853+ , placeholder : Maybe (Placeholder msg)
854+ , label : Label msg
855+ }
856+
857+
858+{-| -}
859+textHelper : TextInput -> List (Attribute msg) -> Text msg -> Element msg
860+textHelper textInput attrs textOptions =
861+ let
862+ withDefaults =
863+ defaultTextBoxStyle ++ attrs
864+
865+ redistributed =
866+ redistribute (textInput.type_ == TextArea)
867+ (isStacked textOptions.label)
868+ withDefaults
869+
870+ onlySpacing attr =
871+ case attr of
872+ Internal.StyleClass _ (Internal.SpacingStyle _ _ _) ->
873+ True
874+
875+ _ ->
876+ False
877+
878+ getPadding attr =
879+ case attr of
880+ Internal.StyleClass cls (Internal.PaddingStyle pad t r b l) ->
881+ -- The - 3 is here to prevent accidental triggering of scrollbars
882+ -- when things are off by a pixel or two.
883+ -- (or at least when the browser *thinks* it's off by a pixel or two)
884+ Just
885+ { top = max 0 (floor (t - 3))
886+ , right = max 0 (floor (r - 3))
887+ , bottom = max 0 (floor (b - 3))
888+ , left = max 0 (floor (l - 3))
889+ }
890+
891+ _ ->
892+ Nothing
893+
894+ heightConstrained =
895+ case textInput.type_ of
896+ TextInputNode inputType ->
897+ False
898+
899+ TextArea ->
900+ withDefaults
901+ |> List.filterMap getHeight
902+ |> List.reverse
903+ |> List.head
904+ |> Maybe.map isConstrained
905+ |> Maybe.withDefault False
906+
907+ parentPadding =
908+ withDefaults
909+ |> List.filterMap getPadding
910+ |> List.reverse
911+ |> List.head
912+ |> Maybe.withDefault
913+ { top = 0
914+ , right = 0
915+ , bottom = 0
916+ , left = 0
917+ }
918+
919+ inputElement =
920+ Internal.element
921+ Internal.asEl
922+ (case textInput.type_ of
923+ TextInputNode inputType ->
924+ Internal.NodeName "input"
925+
926+ TextArea ->
927+ Internal.NodeName "textarea"
928+ )
929+ ((case textInput.type_ of
930+ TextInputNode inputType ->
931+ -- Note: Due to a weird edgecase in...Edge...
932+ -- `type` needs to come _before_ `value`
933+ -- More reading: https://github.com/mdgriffith/elm-ui/pull/94/commits/4f493a27001ccc3cf1f2baa82e092c35d3811876
934+ [ Internal.Attr (Html.Attributes.type_ inputType)
935+ , Internal.htmlClass classes.inputText
936+ ]
937+
938+ TextArea ->
939+ [ Element.clip
940+ , Element.height Element.fill
941+ , Internal.htmlClass classes.inputMultiline
942+ , calcMoveToCompensateForPadding withDefaults
943+
944+ -- The only reason we do this padding trick is so that when the user clicks in the padding,
945+ -- that the cursor will reset correctly.
946+ -- This could probably be combined with the above `calcMoveToCompensateForPadding`
947+ , Element.paddingEach parentPadding
948+ , Internal.Attr (Html.Attributes.style "margin" (renderBox (negateBox parentPadding)))
949+ , Internal.Attr (Html.Attributes.style "box-sizing" "content-box")
950+ ]
951+ )
952+ ++ [ value textOptions.text
953+ , Internal.Attr (Html.Events.onInput textOptions.onChange)
954+ , hiddenLabelAttribute textOptions.label
955+ , spellcheck textInput.spellchecked
956+ , Maybe.map autofill textInput.autofill
957+ |> Maybe.withDefault Internal.NoAttribute
958+ ]
959+ ++ redistributed.input
960+ )
961+ (Internal.Unkeyed [])
962+
963+ wrappedInput =
964+ case textInput.type_ of
965+ TextArea ->
966+ -- textarea with height-content means that
967+ -- the input element is rendered `inFront` with a transparent background
968+ -- Then the input text is rendered as the space filling element.
969+ Internal.element
970+ Internal.asEl
971+ Internal.div
972+ ((if heightConstrained then
973+ (::) Element.scrollbarY
974+
975+ else
976+ identity
977+ )
978+ [ Element.width Element.fill
979+ , if List.any hasFocusStyle withDefaults then
980+ Internal.NoAttribute
981+
982+ else
983+ Internal.htmlClass classes.focusedWithin
984+ , Internal.htmlClass classes.inputMultilineWrapper
985+ ]
986+ ++ redistributed.parent
987+ )
988+ (Internal.Unkeyed
989+ [ Internal.element
990+ Internal.asParagraph
991+ Internal.div
992+ (Element.width Element.fill
993+ :: Element.height Element.fill
994+ :: Element.inFront inputElement
995+ :: Internal.htmlClass classes.inputMultilineParent
996+ :: redistributed.wrapper
997+ )
998+ (Internal.Unkeyed
999+ (if textOptions.text == "" then
1000+ case textOptions.placeholder of
1001+ Nothing ->
1002+ -- Without this, firefox will make the text area lose focus
1003+ -- if the input is empty and you mash the keyboard
1004+ [ Element.text "\u{00A0}"
1005+ ]
1006+
1007+ Just place ->
1008+ [ renderPlaceholder place
1009+ []
1010+ (textOptions.text == "")
1011+ ]
1012+
1013+ else
1014+ [ Internal.unstyled
1015+ (Html.span [ Html.Attributes.class classes.inputMultilineFiller ]
1016+ -- We append a non-breaking space to the end of the content so that newlines don't get chomped.
1017+ [ Html.text (textOptions.text ++ "\u{00A0}")
1018+ ]
1019+ )
1020+ ]
1021+ )
1022+ )
1023+ ]
1024+ )
1025+
1026+ TextInputNode inputType ->
1027+ Internal.element
1028+ Internal.asEl
1029+ Internal.div
1030+ (Element.width Element.fill
1031+ :: (if List.any hasFocusStyle withDefaults then
1032+ Internal.NoAttribute
1033+
1034+ else
1035+ Internal.htmlClass classes.focusedWithin
1036+ )
1037+ :: List.concat
1038+ [ redistributed.parent
1039+ , case textOptions.placeholder of
1040+ Nothing ->
1041+ []
1042+
1043+ Just place ->
1044+ [ Element.behindContent
1045+ (renderPlaceholder place redistributed.cover (textOptions.text == ""))
1046+ ]
1047+ ]
1048+ )
1049+ (Internal.Unkeyed [ inputElement ])
1050+ in
1051+ applyLabel
1052+ (Internal.Class Flag.cursor classes.cursorText
1053+ :: (if isHiddenLabel textOptions.label then
1054+ Internal.NoAttribute
1055+
1056+ else
1057+ Element.spacing
1058+ 5
1059+ )
1060+ :: Region.announce
1061+ :: redistributed.fullParent
1062+ )
1063+ textOptions.label
1064+ wrappedInput
1065+
1066+
1067+getHeight attr =
1068+ case attr of
1069+ Internal.Height h ->
1070+ Just h
1071+
1072+ _ ->
1073+ Nothing
1074+
1075+
1076+negateBox box =
1077+ { top = negate box.top
1078+ , right = negate box.right
1079+ , bottom = negate box.bottom
1080+ , left = negate box.left
1081+ }
1082+
1083+
1084+renderBox { top, right, bottom, left } =
1085+ String.fromInt top
1086+ ++ "px "
1087+ ++ String.fromInt right
1088+ ++ "px "
1089+ ++ String.fromInt bottom
1090+ ++ "px "
1091+ ++ String.fromInt left
1092+ ++ "px"
1093+
1094+
1095+renderPlaceholder (Placeholder placeholderAttrs placeholderEl) forPlaceholder on =
1096+ Element.el
1097+ (forPlaceholder
1098+ ++ [ Font.color charcoal
1099+ , Internal.htmlClass (classes.noTextSelection ++ " " ++ classes.passPointerEvents)
1100+ , Element.clip
1101+ , Border.color (Element.rgba 0 0 0 0)
1102+ , Background.color (Element.rgba 0 0 0 0)
1103+ , Element.height Element.fill
1104+ , Element.width Element.fill
1105+ , Element.alpha
1106+ (if on then
1107+ 1
1108+
1109+ else
1110+ 0
1111+ )
1112+ ]
1113+ ++ placeholderAttrs
1114+ )
1115+ placeholderEl
1116+
1117+
1118+{-| Because textareas are now shadowed, where they're rendered twice,
1119+we to move the literal text area up because spacing is based on line height.
1120+-}
1121+calcMoveToCompensateForPadding : List (Attribute msg) -> Attribute msg
1122+calcMoveToCompensateForPadding attrs =
1123+ let
1124+ gatherSpacing attr found =
1125+ case attr of
1126+ Internal.StyleClass _ (Internal.SpacingStyle _ x y) ->
1127+ case found of
1128+ Nothing ->
1129+ Just y
1130+
1131+ _ ->
1132+ found
1133+
1134+ _ ->
1135+ found
1136+ in
1137+ case List.foldr gatherSpacing Nothing attrs of
1138+ Nothing ->
1139+ Internal.NoAttribute
1140+
1141+ Just vSpace ->
1142+ Element.moveUp (toFloat (floor (toFloat vSpace / 2)))
1143+
1144+
1145+{-| Given the list of attributes provided to `Input.multiline` or `Input.text`,
1146+
1147+redistribute them to the parent, the input, or the cover.
1148+
1149+ - fullParent -> Wrapper around label and input
1150+ - parent -> parent of wrapper
1151+ - wrapper -> the element that is here to take up space.
1152+ - cover -> things like placeholders or text areas which are layered on top of input.
1153+ - input -> actual input element
1154+
1155+-}
1156+redistribute :
1157+ Bool
1158+ -> Bool
1159+ -> List (Attribute msg)
1160+ ->
1161+ { fullParent : List (Attribute msg)
1162+ , parent : List (Attribute msg)
1163+ , wrapper : List (Attribute msg)
1164+ , input : List (Attribute msg)
1165+ , cover : List (Attribute msg)
1166+ }
1167+redistribute isMultiline stacked attrs =
1168+ List.foldl (redistributeOver isMultiline stacked)
1169+ { fullParent = []
1170+ , parent = []
1171+ , input = []
1172+ , cover = []
1173+ , wrapper = []
1174+ }
1175+ attrs
1176+ |> (\redist ->
1177+ { parent = List.reverse redist.parent
1178+ , fullParent = List.reverse redist.fullParent
1179+ , wrapper = List.reverse redist.wrapper
1180+ , input = List.reverse redist.input
1181+ , cover = List.reverse redist.cover
1182+ }
1183+ )
1184+
1185+
1186+isFill len =
1187+ case len of
1188+ Internal.Fill _ ->
1189+ True
1190+
1191+ Internal.Content ->
1192+ False
1193+
1194+ Internal.Px _ ->
1195+ False
1196+
1197+ Internal.Min _ l ->
1198+ isFill l
1199+
1200+ Internal.Max _ l ->
1201+ isFill l
1202+
1203+
1204+isShrink len =
1205+ case len of
1206+ Internal.Content ->
1207+ True
1208+
1209+ Internal.Px _ ->
1210+ False
1211+
1212+ Internal.Fill _ ->
1213+ False
1214+
1215+ Internal.Min _ l ->
1216+ isShrink l
1217+
1218+ Internal.Max _ l ->
1219+ isShrink l
1220+
1221+
1222+isConstrained len =
1223+ case len of
1224+ Internal.Content ->
1225+ False
1226+
1227+ Internal.Px _ ->
1228+ True
1229+
1230+ Internal.Fill _ ->
1231+ True
1232+
1233+ Internal.Min _ l ->
1234+ isConstrained l
1235+
1236+ Internal.Max _ l ->
1237+ True
1238+
1239+
1240+isPixel len =
1241+ case len of
1242+ Internal.Content ->
1243+ False
1244+
1245+ Internal.Px _ ->
1246+ True
1247+
1248+ Internal.Fill _ ->
1249+ False
1250+
1251+ Internal.Min _ l ->
1252+ isPixel l
1253+
1254+ Internal.Max _ l ->
1255+ isPixel l
1256+
1257+
1258+{-| isStacked means that the label is above or below
1259+-}
1260+redistributeOver isMultiline stacked attr els =
1261+ case attr of
1262+ Internal.Nearby _ _ ->
1263+ { els | parent = attr :: els.parent }
1264+
1265+ Internal.Width width ->
1266+ if isFill width then
1267+ { els
1268+ | fullParent = attr :: els.fullParent
1269+ , parent = attr :: els.parent
1270+ , input = attr :: els.input
1271+ }
1272+
1273+ else if stacked then
1274+ { els
1275+ | fullParent = attr :: els.fullParent
1276+ }
1277+
1278+ else
1279+ { els
1280+ | parent = attr :: els.parent
1281+ }
1282+
1283+ Internal.Height height ->
1284+ if not stacked then
1285+ { els
1286+ | fullParent = attr :: els.fullParent
1287+ , parent = attr :: els.parent
1288+ }
1289+
1290+ else if isFill height then
1291+ { els
1292+ | fullParent = attr :: els.fullParent
1293+ , parent = attr :: els.parent
1294+ }
1295+
1296+ else if isPixel height then
1297+ { els | parent = attr :: els.parent }
1298+
1299+ else
1300+ { els
1301+ | parent = attr :: els.parent
1302+ }
1303+
1304+ Internal.AlignX _ ->
1305+ { els | fullParent = attr :: els.fullParent }
1306+
1307+ Internal.AlignY _ ->
1308+ { els | fullParent = attr :: els.fullParent }
1309+
1310+ Internal.StyleClass _ (Internal.SpacingStyle _ _ _) ->
1311+ { els
1312+ | fullParent = attr :: els.fullParent
1313+ , parent = attr :: els.parent
1314+ , input = attr :: els.input
1315+ , wrapper = attr :: els.wrapper
1316+ }
1317+
1318+ Internal.StyleClass cls (Internal.PaddingStyle pad t r b l) ->
1319+ if isMultiline then
1320+ { els
1321+ | parent = attr :: els.parent
1322+ , cover = attr :: els.cover
1323+ }
1324+
1325+ else
1326+ let
1327+ newHeight =
1328+ Element.htmlAttribute
1329+ (Html.Attributes.style
1330+ "height"
1331+ ("calc(1.0em + " ++ String.fromFloat (2 * min t b) ++ "px)")
1332+ )
1333+
1334+ newLineHeight =
1335+ Element.htmlAttribute
1336+ (Html.Attributes.style
1337+ "line-height"
1338+ ("calc(1.0em + " ++ String.fromFloat (2 * min t b) ++ "px)")
1339+ )
1340+
1341+ newTop =
1342+ t - min t b
1343+
1344+ newBottom =
1345+ b - min t b
1346+
1347+ reducedVerticalPadding =
1348+ Internal.StyleClass Flag.padding
1349+ (Internal.PaddingStyle
1350+ (Internal.paddingNameFloat
1351+ newTop
1352+ r
1353+ newBottom
1354+ l
1355+ )
1356+ newTop
1357+ r
1358+ newBottom
1359+ l
1360+ )
1361+ in
1362+ { els
1363+ | parent = reducedVerticalPadding :: els.parent
1364+ , input = newHeight :: newLineHeight :: els.input
1365+ , cover = attr :: els.cover
1366+ }
1367+
1368+ Internal.StyleClass _ (Internal.BorderWidth _ _ _ _ _) ->
1369+ { els
1370+ | parent = attr :: els.parent
1371+ , cover = attr :: els.cover
1372+ }
1373+
1374+ Internal.StyleClass _ (Internal.Transform _) ->
1375+ { els
1376+ | parent = attr :: els.parent
1377+ , cover = attr :: els.cover
1378+ }
1379+
1380+ Internal.StyleClass _ (Internal.FontSize _) ->
1381+ { els | fullParent = attr :: els.fullParent }
1382+
1383+ Internal.StyleClass _ (Internal.FontFamily _ _) ->
1384+ { els | fullParent = attr :: els.fullParent }
1385+
1386+ Internal.StyleClass flag cls ->
1387+ { els | parent = attr :: els.parent }
1388+
1389+ Internal.NoAttribute ->
1390+ els
1391+
1392+ Internal.Attr a ->
1393+ { els | input = attr :: els.input }
1394+
1395+ Internal.Describe _ ->
1396+ { els | input = attr :: els.input }
1397+
1398+ Internal.Class _ _ ->
1399+ { els | parent = attr :: els.parent }
1400+
1401+ Internal.TransformComponent _ _ ->
1402+ { els | input = attr :: els.input }
1403+
1404+
1405+{-| -}
1406+text :
1407+ List (Attribute msg)
1408+ ->
1409+ { onChange : String -> msg
1410+ , text : String
1411+ , placeholder : Maybe (Placeholder msg)
1412+ , label : Label msg
1413+ }
1414+ -> Element msg
1415+text =
1416+ textHelper
1417+ { type_ = TextInputNode "text"
1418+ , spellchecked = False
1419+ , autofill = Nothing
1420+ }
1421+
1422+
1423+{-| If spell checking is available, this input will be spellchecked.
1424+-}
1425+spellChecked :
1426+ List (Attribute msg)
1427+ ->
1428+ { onChange : String -> msg
1429+ , text : String
1430+ , placeholder : Maybe (Placeholder msg)
1431+ , label : Label msg
1432+ }
1433+ -> Element msg
1434+spellChecked =
1435+ textHelper
1436+ { type_ = TextInputNode "text"
1437+ , spellchecked = True
1438+ , autofill = Nothing
1439+ }
1440+
1441+
1442+{-| -}
1443+search :
1444+ List (Attribute msg)
1445+ ->
1446+ { onChange : String -> msg
1447+ , text : String
1448+ , placeholder : Maybe (Placeholder msg)
1449+ , label : Label msg
1450+ }
1451+ -> Element msg
1452+search =
1453+ textHelper
1454+ { type_ = TextInputNode "search"
1455+ , spellchecked = False
1456+ , autofill = Nothing
1457+ }
1458+
1459+
1460+{-| A password input that allows the browser to autofill.
1461+
1462+It's `newPassword` instead of just `password` because it gives the browser a hint on what type of password input it is.
1463+
1464+A password takes all the arguments a normal `Input.text` would, and also **show**, which will remove the password mask (e.g. `****` vs `pass1234`)
1465+
1466+-}
1467+newPassword :
1468+ List (Attribute msg)
1469+ ->
1470+ { onChange : String -> msg
1471+ , text : String
1472+ , placeholder : Maybe (Placeholder msg)
1473+ , label : Label msg
1474+ , show : Bool
1475+ }
1476+ -> Element msg
1477+newPassword attrs pass =
1478+ textHelper
1479+ { type_ =
1480+ TextInputNode <|
1481+ if pass.show then
1482+ "text"
1483+
1484+ else
1485+ "password"
1486+ , spellchecked = False
1487+ , autofill = Just "new-password"
1488+ }
1489+ attrs
1490+ { onChange = pass.onChange
1491+ , text = pass.text
1492+ , placeholder = pass.placeholder
1493+ , label = pass.label
1494+ }
1495+
1496+
1497+{-| -}
1498+currentPassword :
1499+ List (Attribute msg)
1500+ ->
1501+ { onChange : String -> msg
1502+ , text : String
1503+ , placeholder : Maybe (Placeholder msg)
1504+ , label : Label msg
1505+ , show : Bool
1506+ }
1507+ -> Element msg
1508+currentPassword attrs pass =
1509+ textHelper
1510+ { type_ =
1511+ TextInputNode <|
1512+ if pass.show then
1513+ "text"
1514+
1515+ else
1516+ "password"
1517+ , spellchecked = False
1518+ , autofill = Just "current-password"
1519+ }
1520+ attrs
1521+ { onChange = pass.onChange
1522+ , text = pass.text
1523+ , placeholder = pass.placeholder
1524+ , label = pass.label
1525+ }
1526+
1527+
1528+{-| -}
1529+username :
1530+ List (Attribute msg)
1531+ ->
1532+ { onChange : String -> msg
1533+ , text : String
1534+ , placeholder : Maybe (Placeholder msg)
1535+ , label : Label msg
1536+ }
1537+ -> Element msg
1538+username =
1539+ textHelper
1540+ { type_ = TextInputNode "text"
1541+ , spellchecked = False
1542+ , autofill = Just "username"
1543+ }
1544+
1545+
1546+{-| -}
1547+email :
1548+ List (Attribute msg)
1549+ ->
1550+ { onChange : String -> msg
1551+ , text : String
1552+ , placeholder : Maybe (Placeholder msg)
1553+ , label : Label msg
1554+ }
1555+ -> Element msg
1556+email =
1557+ textHelper
1558+ { type_ = TextInputNode "email"
1559+ , spellchecked = False
1560+ , autofill = Just "email"
1561+ }
1562+
1563+
1564+{-| A multiline text input.
1565+
1566+By default it will have a minimum height of one line and resize based on it's contents.
1567+
1568+Use `Element.spacing` to change its line-height.
1569+
1570+-}
1571+multiline :
1572+ List (Attribute msg)
1573+ ->
1574+ { onChange : String -> msg
1575+ , text : String
1576+ , placeholder : Maybe (Placeholder msg)
1577+ , label : Label msg
1578+ , spellcheck : Bool
1579+ }
1580+ -> Element msg
1581+multiline attrs multi =
1582+ textHelper
1583+ { type_ =
1584+ TextArea
1585+ , spellchecked = multi.spellcheck
1586+ , autofill = Nothing
1587+ }
1588+ attrs
1589+ { onChange = multi.onChange
1590+ , text = multi.text
1591+ , placeholder = multi.placeholder
1592+ , label = multi.label
1593+ }
1594+
1595+
1596+isHiddenLabel label =
1597+ case label of
1598+ HiddenLabel _ ->
1599+ True
1600+
1601+ _ ->
1602+ False
1603+
1604+
1605+applyLabel : List (Attribute msg) -> Label msg -> Element msg -> Element msg
1606+applyLabel attrs label input =
1607+ case label of
1608+ HiddenLabel labelText ->
1609+ -- NOTE: This means that the label is applied outside of this function!
1610+ -- It would be nice to unify this logic, but it's a little tricky
1611+ Internal.element
1612+ Internal.asColumn
1613+ (Internal.NodeName "label")
1614+ attrs
1615+ (Internal.Unkeyed [ input ])
1616+
1617+ Label position labelAttrs labelChild ->
1618+ let
1619+ labelElement =
1620+ Internal.element
1621+ Internal.asEl
1622+ Internal.div
1623+ labelAttrs
1624+ (Internal.Unkeyed [ labelChild ])
1625+ in
1626+ case position of
1627+ Above ->
1628+ Internal.element
1629+ Internal.asColumn
1630+ (Internal.NodeName "label")
1631+ (Internal.htmlClass classes.inputLabel :: attrs)
1632+ (Internal.Unkeyed [ labelElement, input ])
1633+
1634+ Below ->
1635+ Internal.element
1636+ Internal.asColumn
1637+ (Internal.NodeName "label")
1638+ (Internal.htmlClass classes.inputLabel :: attrs)
1639+ (Internal.Unkeyed [ input, labelElement ])
1640+
1641+ OnRight ->
1642+ Internal.element
1643+ Internal.asRow
1644+ (Internal.NodeName "label")
1645+ (Internal.htmlClass classes.inputLabel :: attrs)
1646+ (Internal.Unkeyed [ input, labelElement ])
1647+
1648+ OnLeft ->
1649+ Internal.element
1650+ Internal.asRow
1651+ (Internal.NodeName "label")
1652+ (Internal.htmlClass classes.inputLabel :: attrs)
1653+ (Internal.Unkeyed [ labelElement, input ])
1654+
1655+
1656+{-| -}
1657+type Option value msg
1658+ = Option value (OptionState -> Element msg)
1659+
1660+
1661+{-| -}
1662+type OptionState
1663+ = Idle
1664+ | Focused
1665+ | Selected
1666+
1667+
1668+{-| Add a choice to your radio element. This will be rendered with the default radio icon.
1669+-}
1670+option : value -> Element msg -> Option value msg
1671+option val txt =
1672+ Option val (defaultRadioOption txt)
1673+
1674+
1675+{-| Customize exactly what your radio option should look like in different states.
1676+-}
1677+optionWith : value -> (OptionState -> Element msg) -> Option value msg
1678+optionWith val view =
1679+ Option val view
1680+
1681+
1682+{-| -}
1683+radio :
1684+ List (Attribute msg)
1685+ ->
1686+ { onChange : option -> msg
1687+ , options : List (Option option msg)
1688+ , selected : Maybe option
1689+ , label : Label msg
1690+ }
1691+ -> Element msg
1692+radio =
1693+ radioHelper Column
1694+
1695+
1696+{-| Same as radio, but displayed as a row
1697+-}
1698+radioRow :
1699+ List (Attribute msg)
1700+ ->
1701+ { onChange : option -> msg
1702+ , options : List (Option option msg)
1703+ , selected : Maybe option
1704+ , label : Label msg
1705+ }
1706+ -> Element msg
1707+radioRow =
1708+ radioHelper Row
1709+
1710+
1711+defaultRadioOption : Element msg -> OptionState -> Element msg
1712+defaultRadioOption optionLabel status =
1713+ Element.row
1714+ [ Element.spacing 10
1715+ , Element.alignLeft
1716+ , Element.width Element.shrink
1717+ ]
1718+ [ Element.el
1719+ [ Element.width (Element.px 14)
1720+ , Element.height (Element.px 14)
1721+ , Background.color white
1722+ , Border.rounded 7
1723+ , case status of
1724+ Selected ->
1725+ Internal.htmlClass "focusable"
1726+
1727+ _ ->
1728+ Internal.NoAttribute
1729+
1730+ -- , Border.shadow <|
1731+ -- -- case status of
1732+ -- -- Idle ->
1733+ -- -- { offset = ( 0, 0 )
1734+ -- -- , blur =
1735+ -- -- 1
1736+ -- -- , color = Color.rgb 235 235 235
1737+ -- -- }
1738+ -- -- Focused ->
1739+ -- -- { offset = ( 0, 0 )
1740+ -- -- , blur =
1741+ -- -- 0
1742+ -- -- , color = Color.rgba 235 235 235 0
1743+ -- -- }
1744+ -- -- Selected ->
1745+ -- { offset = ( 0, 0 )
1746+ -- , blur =
1747+ -- 1
1748+ -- , color = Color.rgba 235 235 235 0
1749+ -- }
1750+ , Border.width <|
1751+ case status of
1752+ Idle ->
1753+ 1
1754+
1755+ Focused ->
1756+ 1
1757+
1758+ Selected ->
1759+ 5
1760+ , Border.color <|
1761+ case status of
1762+ Idle ->
1763+ Element.rgb (208 / 255) (208 / 255) (208 / 255)
1764+
1765+ Focused ->
1766+ Element.rgb (208 / 255) (208 / 255) (208 / 255)
1767+
1768+ Selected ->
1769+ Element.rgb (59 / 255) (153 / 255) (252 / 255)
1770+ ]
1771+ Element.none
1772+ , Element.el [ Element.width Element.fill, Internal.htmlClass "unfocusable" ] optionLabel
1773+ ]
1774+
1775+
1776+radioHelper :
1777+ Orientation
1778+ -> List (Attribute msg)
1779+ ->
1780+ { onChange : option -> msg
1781+ , options : List (Option option msg)
1782+ , selected : Maybe option
1783+ , label : Label msg
1784+ }
1785+ -> Element msg
1786+radioHelper orientation attrs input =
1787+ let
1788+ renderOption (Option val view) =
1789+ let
1790+ status =
1791+ if Just val == input.selected then
1792+ Selected
1793+
1794+ else
1795+ Idle
1796+ in
1797+ Element.el
1798+ [ Element.pointer
1799+ , case orientation of
1800+ Row ->
1801+ Element.width Element.shrink
1802+
1803+ Column ->
1804+ Element.width Element.fill
1805+ , Events.onClick (input.onChange val)
1806+ , case status of
1807+ Selected ->
1808+ Internal.Attr <|
1809+ Html.Attributes.attribute "aria-checked"
1810+ "true"
1811+
1812+ _ ->
1813+ Internal.Attr <|
1814+ Html.Attributes.attribute "aria-checked"
1815+ "false"
1816+ , Internal.Attr <|
1817+ Html.Attributes.attribute "role" "radio"
1818+ ]
1819+ (view status)
1820+
1821+ optionArea =
1822+ case orientation of
1823+ Row ->
1824+ row (hiddenLabelAttribute input.label :: attrs)
1825+ (List.map renderOption input.options)
1826+
1827+ Column ->
1828+ column (hiddenLabelAttribute input.label :: attrs)
1829+ (List.map renderOption input.options)
1830+
1831+ prevNext =
1832+ case input.options of
1833+ [] ->
1834+ Nothing
1835+
1836+ (Option val _) :: _ ->
1837+ List.foldl track ( NotFound, val, val ) input.options
1838+ |> (\( found, b, a ) ->
1839+ case found of
1840+ NotFound ->
1841+ Just ( b, val )
1842+
1843+ BeforeFound ->
1844+ Just ( b, val )
1845+
1846+ _ ->
1847+ Just ( b, a )
1848+ )
1849+
1850+ track opt ( found, prev, nxt ) =
1851+ case opt of
1852+ Option val _ ->
1853+ case found of
1854+ NotFound ->
1855+ if Just val == input.selected then
1856+ ( BeforeFound, prev, nxt )
1857+
1858+ else
1859+ ( found, val, nxt )
1860+
1861+ BeforeFound ->
1862+ ( AfterFound, prev, val )
1863+
1864+ AfterFound ->
1865+ ( found, prev, nxt )
1866+
1867+ events =
1868+ Internal.get
1869+ attrs
1870+ <|
1871+ \attr ->
1872+ case attr of
1873+ Internal.Width (Internal.Fill _) ->
1874+ True
1875+
1876+ Internal.Height (Internal.Fill _) ->
1877+ True
1878+
1879+ Internal.Attr _ ->
1880+ True
1881+
1882+ _ ->
1883+ False
1884+ in
1885+ applyLabel
1886+ (List.filterMap identity
1887+ [ Just Element.alignLeft
1888+ , Just (tabindex 0)
1889+ , Just (Internal.htmlClass "focus")
1890+ , Just Region.announce
1891+ , Just <|
1892+ Internal.Attr <|
1893+ Html.Attributes.attribute "role" "radiogroup"
1894+ , case prevNext of
1895+ Nothing ->
1896+ Nothing
1897+
1898+ Just ( prev, next ) ->
1899+ Just
1900+ (onKeyLookup <|
1901+ \code ->
1902+ if code == leftArrow then
1903+ Just (input.onChange prev)
1904+
1905+ else if code == upArrow then
1906+ Just (input.onChange prev)
1907+
1908+ else if code == rightArrow then
1909+ Just (input.onChange next)
1910+
1911+ else if code == downArrow then
1912+ Just (input.onChange next)
1913+
1914+ else if code == space then
1915+ case input.selected of
1916+ Nothing ->
1917+ Just (input.onChange prev)
1918+
1919+ _ ->
1920+ Nothing
1921+
1922+ else
1923+ Nothing
1924+ )
1925+ ]
1926+ ++ events
1927+ -- ++ hideIfEverythingisInvisible
1928+ )
1929+ input.label
1930+ optionArea
1931+
1932+
1933+type Found
1934+ = NotFound
1935+ | BeforeFound
1936+ | AfterFound
1937+
1938+
1939+type Orientation
1940+ = Row
1941+ | Column
1942+
1943+
1944+column : List (Attribute msg) -> List (Internal.Element msg) -> Internal.Element msg
1945+column attributes children =
1946+ Internal.element
1947+ Internal.asColumn
1948+ Internal.div
1949+ (Element.height Element.shrink
1950+ :: Element.width Element.fill
1951+ :: attributes
1952+ )
1953+ (Internal.Unkeyed children)
1954+
1955+
1956+row : List (Attribute msg) -> List (Internal.Element msg) -> Internal.Element msg
1957+row attributes children =
1958+ Internal.element
1959+ Internal.asRow
1960+ Internal.div
1961+ (Element.width Element.fill
1962+ :: attributes
1963+ )
1964+ (Internal.Unkeyed children)
1965+
1966+
1967+
1968+{- Event Handlers -}
1969+
1970+
1971+{-| -}
1972+onEnter : msg -> Attribute msg
1973+onEnter msg =
1974+ onKey enter msg
1975+
1976+
1977+{-| -}
1978+onSpace : msg -> Attribute msg
1979+onSpace msg =
1980+ onKey space msg
1981+
1982+
1983+{-| -}
1984+onUpArrow : msg -> Attribute msg
1985+onUpArrow msg =
1986+ onKey upArrow msg
1987+
1988+
1989+{-| -}
1990+onRightArrow : msg -> Attribute msg
1991+onRightArrow msg =
1992+ onKey rightArrow msg
1993+
1994+
1995+{-| -}
1996+onLeftArrow : msg -> Attribute msg
1997+onLeftArrow msg =
1998+ onKey leftArrow msg
1999+
2000+
2001+{-| -}
2002+onDownArrow : msg -> Attribute msg
2003+onDownArrow msg =
2004+ onKey downArrow msg
2005+
2006+
2007+enter : String
2008+enter =
2009+ "Enter"
2010+
2011+
2012+tab : String
2013+tab =
2014+ "Tab"
2015+
2016+
2017+delete : String
2018+delete =
2019+ "Delete"
2020+
2021+
2022+backspace : String
2023+backspace =
2024+ "Backspace"
2025+
2026+
2027+upArrow : String
2028+upArrow =
2029+ "ArrowUp"
2030+
2031+
2032+leftArrow : String
2033+leftArrow =
2034+ "ArrowLeft"
2035+
2036+
2037+rightArrow : String
2038+rightArrow =
2039+ "ArrowRight"
2040+
2041+
2042+downArrow : String
2043+downArrow =
2044+ "ArrowDown"
2045+
2046+
2047+space : String
2048+space =
2049+ " "
2050+
2051+
2052+{-| -}
2053+onKey : String -> msg -> Attribute msg
2054+onKey desiredCode msg =
2055+ let
2056+ decode code =
2057+ if code == desiredCode then
2058+ Json.succeed msg
2059+
2060+ else
2061+ Json.fail "Not the enter key"
2062+
2063+ isKey =
2064+ Json.field "key" Json.string
2065+ |> Json.andThen decode
2066+ in
2067+ Internal.Attr <|
2068+ Html.Events.preventDefaultOn "keyup"
2069+ (Json.map (\fired -> ( fired, True )) isKey)
2070+
2071+
2072+
2073+-- preventKeydown : String -> a -> Attribute a
2074+-- preventKeydown desiredCode msg =
2075+-- let
2076+-- decode code =
2077+-- if code == desiredCode then
2078+-- Json.succeed msg
2079+-- else
2080+-- Json.fail "Not the enter key"
2081+-- isKey =
2082+-- Json.field "key" Json.string
2083+-- |> Json.andThen decode
2084+-- in
2085+-- Events.onWithOptions "keydown"
2086+-- { stopPropagation = False
2087+-- , preventDefault = True
2088+-- }
2089+-- isKey
2090+
2091+
2092+{-| -}
2093+onKeyLookup : (String -> Maybe msg) -> Attribute msg
2094+onKeyLookup lookup =
2095+ let
2096+ decode code =
2097+ case lookup code of
2098+ Nothing ->
2099+ Json.fail "No key matched"
2100+
2101+ Just msg ->
2102+ Json.succeed msg
2103+
2104+ isKey =
2105+ Json.field "key" Json.string
2106+ |> Json.andThen decode
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
2110+ Internal.Attr <|
2111+ Html.Events.preventDefaultOn "keydown"
2112+ (Json.map (\fired -> ( fired, True )) isKey)
2113+
2114+
2115+{-| -}
2116+onFocusOut : msg -> Attribute msg
2117+onFocusOut msg =
2118+ Internal.Attr <| Html.Events.on "focusout" (Json.succeed msg)
2119+
2120+
2121+{-| -}
2122+onFocusIn : msg -> Attribute msg
2123+onFocusIn msg =
2124+ Internal.Attr <| Html.Events.on "focusin" (Json.succeed msg)
2125+
2126+
2127+selected : Bool -> Attribute msg
2128+selected =
2129+ Internal.Attr << Html.Attributes.selected
2130+
2131+
2132+name : String -> Attribute msg
2133+name =
2134+ Internal.Attr << Html.Attributes.name
2135+
2136+
2137+value : String -> Attribute msg
2138+value =
2139+ Internal.Attr << Html.Attributes.value
2140+
2141+
2142+tabindex : Int -> Attribute msg
2143+tabindex =
2144+ Internal.Attr << Html.Attributes.tabindex
2145+
2146+
2147+disabled : Bool -> Attribute msg
2148+disabled =
2149+ Internal.Attr << Html.Attributes.disabled
2150+
2151+
2152+spellcheck : Bool -> Attribute msg
2153+spellcheck =
2154+ Internal.Attr << Html.Attributes.spellcheck
2155+
2156+
2157+readonly : Bool -> Attribute msg
2158+readonly =
2159+ Internal.Attr << Html.Attributes.readonly
2160+
2161+
2162+autofill : String -> Attribute msg
2163+autofill =
2164+ Internal.Attr << Html.Attributes.attribute "autocomplete"
2165+
2166+
2167+{-| Attach this attribute to any `Input` that you would like to be automatically focused when the page loads.
2168+
2169+You should only have a maximum of one per page.
2170+
2171+-}
2172+focusedOnLoad : Attribute msg
2173+focusedOnLoad =
2174+ Internal.Attr <| Html.Attributes.autofocus True
2175+
2176+
2177+
2178+{- Style Defaults -}
2179+
2180+
2181+defaultTextBoxStyle : List (Attribute msg)
2182+defaultTextBoxStyle =
2183+ [ defaultTextPadding
2184+ , Border.rounded 3
2185+ , Border.color darkGrey
2186+ , Background.color white
2187+ , Border.width 1
2188+ , Element.spacing 5
2189+ , Element.width Element.fill
2190+ , Element.height Element.shrink
2191+ ]
2192+
2193+
2194+defaultTextPadding : Attribute msg
2195+defaultTextPadding =
2196+ Element.paddingXY 12 12
2197+
2198+
2199+{-| The blue default checked box icon.
2200+
2201+You'll likely want to make your own checkbox at some point that fits your design.
2202+
2203+-}
2204+defaultCheckbox : Bool -> Element msg
2205+defaultCheckbox checked =
2206+ Element.el
2207+ [ Internal.htmlClass "focusable"
2208+ , Element.width
2209+ (Element.px 14)
2210+ , Element.height (Element.px 14)
2211+ , Font.color white
2212+ , Element.centerY
2213+ , Font.size 9
2214+ , Font.center
2215+ , Border.rounded 3
2216+ , Border.color <|
2217+ if checked then
2218+ Element.rgb (59 / 255) (153 / 255) (252 / 255)
2219+
2220+ else
2221+ Element.rgb (211 / 255) (211 / 255) (211 / 255)
2222+ , Border.shadow
2223+ { offset = ( 0, 0 )
2224+ , blur = 1
2225+ , size = 1
2226+ , color =
2227+ if checked then
2228+ Element.rgba (238 / 255) (238 / 255) (238 / 255) 0
2229+
2230+ else
2231+ Element.rgb (238 / 255) (238 / 255) (238 / 255)
2232+ }
2233+ , Background.color <|
2234+ if checked then
2235+ Element.rgb (59 / 255) (153 / 255) (252 / 255)
2236+
2237+ else
2238+ white
2239+ , Border.width <|
2240+ if checked then
2241+ 0
2242+
2243+ else
2244+ 1
2245+ , Element.inFront
2246+ (Element.el
2247+ [ Border.color white
2248+ , Element.height (Element.px 6)
2249+ , Element.width (Element.px 9)
2250+ , Element.rotate (degrees -45)
2251+ , Element.centerX
2252+ , Element.centerY
2253+ , Element.moveUp 1
2254+ , Element.transparent (not checked)
2255+ , Border.widthEach
2256+ { top = 0
2257+ , left = 2
2258+ , bottom = 2
2259+ , right = 0
2260+ }
2261+ ]
2262+ Element.none
2263+ )
2264+ ]
2265+ Element.none
deps/elm-ui/src/Element/Keyed.elmnew file+70
@@ -0,0 +1,70 @@
1+module Element.Keyed exposing (el, column, row)
2+
3+{-| Notes from the `Html.Keyed` on how keyed works:
4+
5+---
6+
7+A keyed node helps optimize cases where children are getting added, moved, removed, etc. Common examples include:
8+
9+ - The user can delete items from a list.
10+ - The user can create new items in a list.
11+ - You can sort a list based on name or date or whatever.
12+
13+When you use a keyed node, every child is paired with a string identifier. This makes it possible for the underlying diffing algorithm to reuse nodes more efficiently.
14+
15+This means if a key is changed between renders, then the diffing step will be skipped and the node will be forced to rerender.
16+
17+---
18+
19+@docs el, column, row
20+
21+-}
22+
23+import Element exposing (Attribute, Element, fill, height, shrink, width)
24+import Internal.Model as Internal
25+import Internal.Style exposing (classes)
26+
27+
28+{-| -}
29+el : List (Attribute msg) -> ( String, Element msg ) -> Element msg
30+el attrs child =
31+ Internal.element
32+ Internal.asEl
33+ Internal.div
34+ (width shrink
35+ :: height shrink
36+ :: attrs
37+ )
38+ (Internal.Keyed [ child ])
39+
40+
41+{-| -}
42+row : List (Attribute msg) -> List ( String, Element msg ) -> Element msg
43+row attrs children =
44+ Internal.element
45+ Internal.asRow
46+ Internal.div
47+ (Internal.htmlClass (classes.contentLeft ++ " " ++ classes.contentCenterY)
48+ :: width shrink
49+ :: height shrink
50+ :: attrs
51+ )
52+ (Internal.Keyed children)
53+
54+
55+{-| -}
56+column : List (Attribute msg) -> List ( String, Element msg ) -> Element msg
57+column attrs children =
58+ Internal.element
59+ Internal.asColumn
60+ Internal.div
61+ (Internal.htmlClass
62+ (classes.contentTop
63+ ++ " "
64+ ++ classes.contentLeft
65+ )
66+ :: height shrink
67+ :: width shrink
68+ :: attrs
69+ )
70+ (Internal.Keyed children)
deps/elm-ui/src/Element/Lazy.elmnew file+117
@@ -0,0 +1,117 @@
1+module Element.Lazy exposing (lazy, lazy2, lazy3, lazy4, lazy5)
2+
3+{-| Same as `Html.lazy`. In case you're unfamiliar, here's a note from the `Html` library!
4+
5+---
6+
7+Since all Elm functions are pure we have a guarantee that the same input
8+will always result in the same output. This module gives us tools to be lazy
9+about building `Html` that utilize this fact.
10+
11+Rather than immediately applying functions to their arguments, the `lazy`
12+functions just bundle the function and arguments up for later. When diffing
13+the old and new virtual DOM, it checks to see if all the arguments are equal
14+by reference. If so, it skips calling the function!
15+
16+This is a really cheap test and often makes things a lot faster, but definitely
17+benchmark to be sure!
18+
19+---
20+
21+@docs lazy, lazy2, lazy3, lazy4, lazy5
22+
23+-}
24+
25+import Internal.Model exposing (..)
26+import VirtualDom
27+
28+
29+{-| -}
30+lazy : (a -> Element msg) -> a -> Element msg
31+lazy fn a =
32+ Unstyled <| VirtualDom.lazy3 apply1 fn a
33+
34+
35+{-| -}
36+lazy2 : (a -> b -> Element msg) -> a -> b -> Element msg
37+lazy2 fn a b =
38+ Unstyled <| VirtualDom.lazy4 apply2 fn a b
39+
40+
41+{-| -}
42+lazy3 : (a -> b -> c -> Element msg) -> a -> b -> c -> Element msg
43+lazy3 fn a b c =
44+ Unstyled <| VirtualDom.lazy5 apply3 fn a b c
45+
46+
47+{-| -}
48+lazy4 : (a -> b -> c -> d -> Element msg) -> a -> b -> c -> d -> Element msg
49+lazy4 fn a b c d =
50+ Unstyled <| VirtualDom.lazy6 apply4 fn a b c d
51+
52+
53+{-| -}
54+lazy5 : (a -> b -> c -> d -> e -> Element msg) -> a -> b -> c -> d -> e -> Element msg
55+lazy5 fn a b c d e =
56+ Unstyled <| VirtualDom.lazy7 apply5 fn a b c d e
57+
58+
59+apply1 fn a =
60+ embed (fn a)
61+
62+
63+apply2 fn a b =
64+ embed (fn a b)
65+
66+
67+apply3 fn a b c =
68+ embed (fn a b c)
69+
70+
71+apply4 fn a b c d =
72+ embed (fn a b c d)
73+
74+
75+apply5 fn a b c d e =
76+ embed (fn a b c d e)
77+
78+
79+{-| -}
80+embed : Element msg -> LayoutContext -> VirtualDom.Node msg
81+embed x =
82+ case x of
83+ Unstyled html ->
84+ html
85+
86+ Styled styled ->
87+ styled.html
88+ (Internal.Model.OnlyDynamic
89+ { hover = AllowHover
90+ , focus =
91+ { borderColor = Nothing
92+ , shadow = Nothing
93+ , backgroundColor = Nothing
94+ }
95+ , mode = Layout
96+ }
97+ styled.styles
98+ )
99+
100+ -- -- (Just
101+ -- -- (toStyleSheetString
102+ -- { hover = AllowHover
103+ -- , focus =
104+ -- { borderColor = Nothing
105+ -- , shadow = Nothing
106+ -- , backgroundColor = Nothing
107+ -- }
108+ -- , mode = Layout
109+ -- }
110+ -- -- styled.styles
111+ -- -- )
112+ -- -- )
113+ Text text ->
114+ always (VirtualDom.text text)
115+
116+ Empty ->
117+ always (VirtualDom.text "")
deps/elm-ui/src/Element/Region.elmnew file+111
@@ -0,0 +1,111 @@
1+module Element.Region exposing
2+ ( mainContent, navigation, heading, aside, footer
3+ , description
4+ , announce, announceUrgently
5+ )
6+
7+{-| This module is meant to make accessibility easy!
8+
9+These are sign posts that accessibility software like screen readers can use to navigate your app.
10+
11+All you have to do is add them to elements in your app where you see fit.
12+
13+Here's an example of annotating your navigation region:
14+
15+ import Element.Region as Region
16+
17+ myNavigation =
18+ Element.row [ Region.navigation ]
19+ [-- ..your navigation links
20+ ]
21+
22+@docs mainContent, navigation, heading, aside, footer
23+
24+@docs description
25+
26+@docs announce, announceUrgently
27+
28+-}
29+
30+import Element exposing (Attribute)
31+import Internal.Model as Internal exposing (Description(..))
32+
33+
34+{-| -}
35+mainContent : Attribute msg
36+mainContent =
37+ Internal.Describe Main
38+
39+
40+{-| -}
41+aside : Attribute msg
42+aside =
43+ Internal.Describe Complementary
44+
45+
46+{-| -}
47+navigation : Attribute msg
48+navigation =
49+ Internal.Describe Navigation
50+
51+
52+
53+-- form : Attribute msg
54+-- form =
55+-- Internal.Describe Form
56+-- search : Attribute msg
57+-- search =
58+-- Internal.Describe Search
59+
60+
61+{-| -}
62+footer : Attribute msg
63+footer =
64+ Internal.Describe ContentInfo
65+
66+
67+{-| This will mark an element as `h1`, `h2`, etc where possible.
68+
69+Though it's also smart enough to not conflict with existing nodes.
70+
71+So, this code
72+
73+ link [ Region.heading 1 ]
74+ { url = "http://fruits.com"
75+ , label = text "Best site ever"
76+ }
77+
78+will generate
79+
80+ <a href="http://fruits.com">
81+ <h1>Best site ever</h1>
82+ </a>
83+
84+-}
85+heading : Int -> Attribute msg
86+heading =
87+ Internal.Describe << Heading
88+
89+
90+{-| Screen readers will announce changes to this element and potentially interrupt any other announcement.
91+-}
92+announceUrgently : Attribute msg
93+announceUrgently =
94+ Internal.Describe LiveAssertive
95+
96+
97+{-| Screen readers will announce when changes to this element are made.
98+-}
99+announce : Attribute msg
100+announce =
101+ Internal.Describe LivePolite
102+
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+
108+-}
109+description : String -> Attribute msg
110+description =
111+ Internal.Describe << Internal.Label
deps/elm-ui/src/Internal/Flag.elmnew file+325
@@ -0,0 +1,325 @@
1+module Internal.Flag exposing
2+ ( Field(..)
3+ , Flag(..)
4+ , active
5+ , add
6+ , alignBottom
7+ , alignRight
8+ , behind
9+ , bgColor
10+ , bgGradient
11+ , bgImage
12+ , borderColor
13+ , borderRound
14+ , borderStyle
15+ , borderWidth
16+ , centerX
17+ , centerY
18+ , cursor
19+ , flag
20+ , focus
21+ , fontAlignment
22+ , fontColor
23+ , fontFamily
24+ , fontSize
25+ , fontVariant
26+ , fontWeight
27+ , gridPosition
28+ , gridTemplate
29+ , height
30+ , heightBetween
31+ , heightContent
32+ , heightFill
33+ , heightTextAreaContent
34+ , hover
35+ , letterSpacing
36+ , merge
37+ , moveX
38+ , moveY
39+ , none
40+ , overflow
41+ , padding
42+ , present
43+ , rotate
44+ , scale
45+ , shadows
46+ , spacing
47+ , transparency
48+ , txtShadows
49+ , value
50+ , width
51+ , widthBetween
52+ , widthContent
53+ , widthFill
54+ , wordSpacing
55+ , xAlign
56+ , yAlign
57+ )
58+
59+{-| -}
60+
61+import Bitwise
62+
63+
64+type Field
65+ = Field Int Int
66+
67+
68+type Flag
69+ = Flag Int
70+ | Second Int
71+
72+
73+none : Field
74+none =
75+ Field 0 0
76+
77+
78+value myFlag =
79+ case myFlag of
80+ Flag first ->
81+ round (logBase 2 (toFloat first))
82+
83+ Second second ->
84+ round (logBase 2 (toFloat second)) + 32
85+
86+
87+{-| If the query is in the truth, return True
88+-}
89+present : Flag -> Field -> Bool
90+present myFlag (Field fieldOne fieldTwo) =
91+ case myFlag of
92+ Flag first ->
93+ Bitwise.and first fieldOne == first
94+
95+ Second second ->
96+ Bitwise.and second fieldTwo == second
97+
98+
99+{-| Add a flag to a field.
100+-}
101+add : Flag -> Field -> Field
102+add myFlag (Field one two) =
103+ case myFlag of
104+ Flag first ->
105+ Field (Bitwise.or first one) two
106+
107+ Second second ->
108+ Field one (Bitwise.or second two)
109+
110+
111+{-| Generally you want to use `add`, which keeps a distinction between Fields and Flags.
112+
113+Merging will combine two fields
114+
115+-}
116+merge : Field -> Field -> Field
117+merge (Field one two) (Field three four) =
118+ Field (Bitwise.or one three) (Bitwise.or two four)
119+
120+
121+flag : Int -> Flag
122+flag i =
123+ if i > 31 then
124+ Second
125+ (Bitwise.shiftLeftBy (i - 32) 1)
126+
127+ else
128+ Flag
129+ (Bitwise.shiftLeftBy i 1)
130+
131+
132+
133+{- Used for Style invalidation -}
134+
135+
136+transparency =
137+ flag 0
138+
139+
140+padding =
141+ flag 2
142+
143+
144+spacing =
145+ flag 3
146+
147+
148+fontSize =
149+ flag 4
150+
151+
152+fontFamily =
153+ flag 5
154+
155+
156+width =
157+ flag 6
158+
159+
160+height =
161+ flag 7
162+
163+
164+bgColor =
165+ flag 8
166+
167+
168+bgImage =
169+ flag 9
170+
171+
172+bgGradient =
173+ flag 10
174+
175+
176+borderStyle =
177+ flag 11
178+
179+
180+fontAlignment =
181+ flag 12
182+
183+
184+fontWeight =
185+ flag 13
186+
187+
188+fontColor =
189+ flag 14
190+
191+
192+wordSpacing =
193+ flag 15
194+
195+
196+letterSpacing =
197+ flag 16
198+
199+
200+borderRound =
201+ flag 17
202+
203+
204+txtShadows =
205+ flag 18
206+
207+
208+shadows =
209+ flag 19
210+
211+
212+overflow =
213+ flag 20
214+
215+
216+cursor =
217+ flag 21
218+
219+
220+scale =
221+ flag 23
222+
223+
224+rotate =
225+ flag 24
226+
227+
228+moveX =
229+ flag 25
230+
231+
232+moveY =
233+ flag 26
234+
235+
236+borderWidth =
237+ flag 27
238+
239+
240+borderColor =
241+ flag 28
242+
243+
244+yAlign =
245+ flag 29
246+
247+
248+xAlign =
249+ flag 30
250+
251+
252+focus =
253+ flag 31
254+
255+
256+active =
257+ flag 32
258+
259+
260+hover =
261+ flag 33
262+
263+
264+gridTemplate =
265+ flag 34
266+
267+
268+gridPosition =
269+ flag 35
270+
271+
272+
273+{- Notes -}
274+
275+
276+heightContent =
277+ flag 36
278+
279+
280+heightFill =
281+ flag 37
282+
283+
284+widthContent =
285+ flag 38
286+
287+
288+widthFill =
289+ flag 39
290+
291+
292+alignRight =
293+ flag 40
294+
295+
296+alignBottom =
297+ flag 41
298+
299+
300+centerX =
301+ flag 42
302+
303+
304+centerY =
305+ flag 43
306+
307+
308+widthBetween =
309+ flag 44
310+
311+
312+heightBetween =
313+ flag 45
314+
315+
316+behind =
317+ flag 46
318+
319+
320+heightTextAreaContent =
321+ flag 47
322+
323+
324+fontVariant =
325+ flag 48
deps/elm-ui/src/Internal/Grid.elmnew file+270
@@ -0,0 +1,270 @@
1+module Internal.Grid exposing (Around, Layout(..), PositionedElement, RelativePosition(..), build, createGrid, getWidth, relative)
2+
3+{-| Relative positioning within a grid.
4+
5+A relatively positioned grid, means a 3x3 grid with the primary element in the center.
6+
7+-}
8+
9+import Element
10+import Internal.Flag as Flag
11+import Internal.Model as Internal
12+
13+
14+type RelativePosition
15+ = OnRight
16+ | OnLeft
17+ | Above
18+ | Below
19+ | InFront
20+
21+
22+type Layout
23+ = GridElement
24+ | Row
25+ | Column
26+
27+
28+type alias Around alignment msg =
29+ { right : Maybe (PositionedElement alignment msg)
30+ , left : Maybe (PositionedElement alignment msg)
31+ , primary : ( Maybe String, List (Internal.Attribute alignment msg), List (Internal.Element msg) )
32+
33+ -- , primaryWidth : Internal.Length
34+ , defaultWidth : Internal.Length
35+ , below : Maybe (PositionedElement alignment msg)
36+ , above : Maybe (PositionedElement alignment msg)
37+ , inFront : Maybe (PositionedElement alignment msg)
38+ }
39+
40+
41+type alias PositionedElement alignment msg =
42+ { layout : Layout
43+ , child : List (Internal.Element msg)
44+ , attrs : List (Internal.Attribute alignment msg)
45+ , width : Int
46+ , height : Int
47+ }
48+
49+
50+relative : Maybe String -> List (Internal.Attribute alignment msg) -> Around alignment msg -> Internal.Element msg
51+relative node attributes around =
52+ let
53+ ( sX, sY ) =
54+ Internal.getSpacing attributes ( 7, 7 )
55+
56+ make positioned =
57+ Internal.element Internal.noStyleSheet
58+ Internal.asEl
59+ Nothing
60+ positioned.attrs
61+ (Internal.Unkeyed positioned.child)
62+
63+ ( template, children ) =
64+ createGrid ( sX, sY ) around
65+ in
66+ Internal.element Internal.noStyleSheet
67+ Internal.asGrid
68+ node
69+ (template ++ attributes)
70+ (Internal.Unkeyed
71+ children
72+ )
73+
74+
75+createGrid : ( Int, Int ) -> Around alignment msg -> ( List (Internal.Attribute alignment msg1), List (Element.Element msg) )
76+createGrid ( spacingX, spacingY ) nearby =
77+ let
78+ rowCount =
79+ List.sum
80+ [ 1
81+ , if Nothing == nearby.above then
82+ 0
83+
84+ else
85+ 1
86+ , if Nothing == nearby.below then
87+ 0
88+
89+ else
90+ 1
91+ ]
92+
93+ colCount =
94+ List.sum
95+ [ 1
96+ , if Nothing == nearby.left then
97+ 0
98+
99+ else
100+ 1
101+ , if Nothing == nearby.right then
102+ 0
103+
104+ else
105+ 1
106+ ]
107+
108+ rows =
109+ if nearby.above == Nothing then
110+ { above = 0
111+ , primary = 1
112+ , below = 2
113+ }
114+
115+ else
116+ { above = 1
117+ , primary = 2
118+ , below = 3
119+ }
120+
121+ columns =
122+ if Nothing == nearby.left then
123+ { left = 0
124+ , primary = 1
125+ , right = 2
126+ }
127+
128+ else
129+ { left = 1
130+ , primary = 2
131+ , right = 3
132+ }
133+
134+ rowCoord pos =
135+ case pos of
136+ Above ->
137+ rows.above
138+
139+ Below ->
140+ rows.below
141+
142+ OnRight ->
143+ rows.primary
144+
145+ OnLeft ->
146+ rows.primary
147+
148+ InFront ->
149+ rows.primary
150+
151+ colCoord pos =
152+ case pos of
153+ Above ->
154+ columns.primary
155+
156+ Below ->
157+ columns.primary
158+
159+ OnRight ->
160+ columns.right
161+
162+ OnLeft ->
163+ columns.left
164+
165+ InFront ->
166+ columns.primary
167+
168+ place pos el =
169+ build (rowCoord pos) (colCoord pos) spacingX spacingY el
170+ in
171+ ( [ Internal.StyleClass Flag.gridTemplate
172+ (Internal.GridTemplateStyle
173+ { spacing = ( Internal.Px spacingX, Internal.Px spacingY )
174+ , columns =
175+ List.filterMap identity
176+ [ nearby.left
177+ |> Maybe.map (\el -> Maybe.withDefault nearby.defaultWidth (getWidth el.attrs))
178+ , nearby.primary
179+ |> (\( node, attrs, el ) -> getWidth attrs)
180+ |> Maybe.withDefault nearby.defaultWidth
181+ |> Just
182+ , nearby.right
183+ |> Maybe.map (\el -> Maybe.withDefault nearby.defaultWidth (getWidth el.attrs))
184+ ]
185+ , rows = List.map (always Internal.Content) (List.range 1 rowCount)
186+ }
187+ )
188+ ]
189+ , List.filterMap identity
190+ [ Just <|
191+ case nearby.primary of
192+ ( primaryNode, primaryAttrs, primaryChildren ) ->
193+ Internal.element Internal.noStyleSheet
194+ Internal.asEl
195+ primaryNode
196+ (Internal.StyleClass Flag.gridPosition
197+ (Internal.GridPosition
198+ { row = rows.primary
199+ , col = columns.primary
200+ , width = 1
201+ , height = 1
202+ }
203+ )
204+ :: primaryAttrs
205+ )
206+ (Internal.Unkeyed primaryChildren)
207+ , Maybe.map (place OnLeft) nearby.left
208+ , Maybe.map (place OnRight) nearby.right
209+ , Maybe.map (place Above) nearby.above
210+ , Maybe.map (place Below) nearby.below
211+ , Maybe.map (place InFront) nearby.inFront
212+ ]
213+ )
214+
215+
216+build : Int -> Int -> Int -> Int -> { a | attrs : List (Internal.Attribute alignment msg), height : Int, layout : Layout, width : Int, child : List (Internal.Element msg) } -> Internal.Element msg
217+build rowCoord colCoord spacingX spacingY positioned =
218+ let
219+ attributes =
220+ Internal.StyleClass Flag.gridPosition
221+ (Internal.GridPosition
222+ { row = rowCoord
223+ , col = colCoord
224+ , width = positioned.width
225+ , height = positioned.height
226+ }
227+ )
228+ :: Internal.StyleClass Flag.spacing (Internal.SpacingStyle spacingX spacingY)
229+ :: positioned.attrs
230+ in
231+ case positioned.layout of
232+ GridElement ->
233+ Internal.element Internal.noStyleSheet
234+ Internal.asEl
235+ Nothing
236+ attributes
237+ (Internal.Unkeyed <| positioned.child)
238+
239+ Row ->
240+ Internal.element Internal.noStyleSheet
241+ Internal.asRow
242+ Nothing
243+ attributes
244+ (Internal.Unkeyed positioned.child)
245+
246+ Column ->
247+ Internal.element Internal.noStyleSheet
248+ Internal.asColumn
249+ Nothing
250+ attributes
251+ (Internal.Unkeyed positioned.child)
252+
253+
254+getWidth : List (Internal.Attribute align msg) -> Maybe Internal.Length
255+getWidth attrs =
256+ let
257+ widthPlease attr found =
258+ case found of
259+ Just x ->
260+ Just x
261+
262+ Nothing ->
263+ case attr of
264+ Internal.Width w ->
265+ Just w
266+
267+ _ ->
268+ Nothing
269+ in
270+ List.foldr widthPlease Nothing attrs
deps/elm-ui/src/Internal/Model.elmnew file+3564
@@ -0,0 +1,3564 @@
1+module Internal.Model exposing
2+ ( Aligned(..)
3+ , Angle
4+ , Attribute(..)
5+ , Axis(..)
6+ , Children(..)
7+ , Color(..)
8+ , Description(..)
9+ , Element(..)
10+ , EmbedStyle(..)
11+ , FocusStyle
12+ , Font(..)
13+ , Gathered
14+ , HAlign(..)
15+ , HoverSetting(..)
16+ , LayoutContext(..)
17+ , Length(..)
18+ , Location(..)
19+ , NearbyChildren(..)
20+ , NodeName(..)
21+ , Option(..)
22+ , OptionRecord
23+ , Padding(..)
24+ , Property(..)
25+ , PseudoClass(..)
26+ , RenderMode(..)
27+ , Shadow
28+ , Spacing(..)
29+ , Style(..)
30+ , TransformComponent(..)
31+ , Transformation(..)
32+ , VAlign(..)
33+ , Variant(..)
34+ , XYZ
35+ , addNodeName
36+ , addWhen
37+ , alignXName
38+ , alignYName
39+ , asColumn
40+ , asEl
41+ , asGrid
42+ , asParagraph
43+ , asRow
44+ , asTextColumn
45+ , boxShadowClass
46+ , columnClass
47+ , composeTransformation
48+ , contextClasses
49+ , createElement
50+ , defaultOptions
51+ , div
52+ , element
53+ , embedKeyed
54+ , embedWith
55+ , extractSpacingAndPadding
56+ , filter
57+ , finalizeNode
58+ , floatClass
59+ , focusDefaultStyle
60+ , formatBoxShadow
61+ , formatColor
62+ , formatColorClass
63+ , formatDropShadow
64+ , formatTextShadow
65+ , gatherAttrRecursive
66+ , get
67+ , getHeight
68+ , getSpacing
69+ , getStyleName
70+ , getWidth
71+ , gridClass
72+ , htmlClass
73+ , isContent
74+ , lengthClassName
75+ , map
76+ , mapAttr
77+ , mapAttrFromStyle
78+ , noStyleSheet
79+ , onlyStyles
80+ , optionsToRecord
81+ , paddingName
82+ , paddingNameFloat
83+ , pageClass
84+ , paragraphClass
85+ , reduceRecursive
86+ , reduceStyles
87+ , reduceStylesRecursive
88+ , removeNever
89+ , renderFontClassName
90+ , renderHeight
91+ , renderRoot
92+ , renderVariant
93+ , renderWidth
94+ , rootStyle
95+ , rowClass
96+ , singleClass
97+ , spacingName
98+ , tag
99+ , textShadowClass
100+ , toHtml
101+ , toStyleSheet
102+ , transformClass
103+ , unstyled
104+ , unwrapDecorations
105+ , variantName
106+ )
107+
108+{-| -}
109+
110+import Html
111+import Html.Attributes
112+import Html.Keyed
113+import Internal.Flag as Flag exposing (Flag)
114+import Internal.Style exposing (classes, dot)
115+import Json.Encode as Encode
116+import Set exposing (Set)
117+import VirtualDom
118+
119+
120+type Element msg
121+ = Unstyled (LayoutContext -> VirtualDom.Node msg)
122+ | Styled
123+ { styles : List Style
124+ , html : EmbedStyle -> LayoutContext -> VirtualDom.Node msg
125+ }
126+ | Text String
127+ | Empty
128+
129+
130+type EmbedStyle
131+ = NoStyleSheet
132+ | StaticRootAndDynamic OptionRecord (List Style)
133+ | OnlyDynamic OptionRecord (List Style)
134+
135+
136+noStyleSheet : EmbedStyle
137+noStyleSheet =
138+ NoStyleSheet
139+
140+
141+type LayoutContext
142+ = AsRow
143+ | AsColumn
144+ | AsEl
145+ | AsGrid
146+ | AsParagraph
147+ | AsTextColumn
148+
149+
150+type Aligned
151+ = Unaligned
152+ | Aligned (Maybe HAlign) (Maybe VAlign)
153+
154+
155+type HAlign
156+ = Left
157+ | CenterX
158+ | Right
159+
160+
161+type VAlign
162+ = Top
163+ | CenterY
164+ | Bottom
165+
166+
167+type Style
168+ = Style String (List Property)
169+ -- class prop val
170+ | FontFamily String (List Font)
171+ | FontSize Int
172+ -- classname, prop, value
173+ | Single String String String
174+ | Colored String String Color
175+ | SpacingStyle String Int Int
176+ | BorderWidth String Int Int Int Int
177+ | PaddingStyle String Float Float Float Float
178+ | GridTemplateStyle
179+ { spacing : ( Length, Length )
180+ , columns : List Length
181+ , rows : List Length
182+ }
183+ | GridPosition
184+ { row : Int
185+ , col : Int
186+ , width : Int
187+ , height : Int
188+ }
189+ | Transform Transformation
190+ | PseudoSelector PseudoClass (List Style)
191+ | Transparency String Float
192+ | Shadows String String
193+
194+
195+type Transformation
196+ = Untransformed
197+ | Moved XYZ
198+ -- translate, scale, rotate
199+ | FullTransform XYZ XYZ XYZ Angle
200+
201+
202+type PseudoClass
203+ = Focus
204+ | Hover
205+ | Active
206+
207+
208+{-| -}
209+type alias Adjustment =
210+ { capital : Float
211+ , lowercase : Float
212+ , baseline : Float
213+ , descender : Float
214+ }
215+
216+
217+type Font
218+ = Serif
219+ | SansSerif
220+ | Monospace
221+ | Typeface String
222+ | ImportFont String String
223+ | FontWith
224+ { name : String
225+ , adjustment : Maybe Adjustment
226+ , variants : List Variant
227+ }
228+
229+
230+type Variant
231+ = VariantActive String
232+ | VariantOff String
233+ | VariantIndexed String Int
234+
235+
236+renderVariant var =
237+ case var of
238+ VariantActive name ->
239+ "\"" ++ name ++ "\""
240+
241+ VariantOff name ->
242+ "\"" ++ name ++ "\" 0"
243+
244+ VariantIndexed name index ->
245+ "\"" ++ name ++ "\" " ++ String.fromInt index
246+
247+
248+variantName var =
249+ case var of
250+ VariantActive name ->
251+ name
252+
253+ VariantOff name ->
254+ name ++ "-0"
255+
256+ VariantIndexed name index ->
257+ name ++ "-" ++ String.fromInt index
258+
259+
260+renderVariants typeface =
261+ case typeface of
262+ FontWith font ->
263+ Just (String.join ", " (List.map renderVariant font.variants))
264+
265+ _ ->
266+ Nothing
267+
268+
269+isSmallCaps var =
270+ case var of
271+ VariantActive name ->
272+ name == "smcp"
273+
274+ VariantOff name ->
275+ False
276+
277+ VariantIndexed name index ->
278+ name == "smcp" && index == 1
279+
280+
281+hasSmallCaps typeface =
282+ case typeface of
283+ FontWith font ->
284+ List.any isSmallCaps font.variants
285+
286+ _ ->
287+ False
288+
289+
290+type Property
291+ = Property String String
292+
293+
294+type alias XYZ =
295+ ( Float, Float, Float )
296+
297+
298+type alias Angle =
299+ Float
300+
301+
302+type Attribute aligned msg
303+ = NoAttribute
304+ | Attr (VirtualDom.Attribute msg)
305+ | Describe Description
306+ -- invalidation key and literal class
307+ | Class Flag String
308+ -- invalidation key "border-color" as opposed to "border-color-10-10-10" that will be the key for the class
309+ | StyleClass Flag Style
310+ | AlignY VAlign
311+ | AlignX HAlign
312+ | Width Length
313+ | Height Length
314+ | Nearby Location (Element msg)
315+ | TransformComponent Flag TransformComponent
316+
317+
318+type TransformComponent
319+ = MoveX Float
320+ | MoveY Float
321+ | MoveZ Float
322+ | MoveXYZ XYZ
323+ | Rotate XYZ Float
324+ | Scale XYZ
325+
326+
327+type Description
328+ = Main
329+ | Navigation
330+ -- | Search
331+ | ContentInfo
332+ | Complementary
333+ | Heading Int
334+ | Label String
335+ | LivePolite
336+ | LiveAssertive
337+ | Button
338+ | Paragraph
339+
340+
341+type Length
342+ = Px Int
343+ | Content
344+ | Fill Int
345+ | Min Int Length
346+ | Max Int Length
347+
348+
349+type Axis
350+ = XAxis
351+ | YAxis
352+ | AllAxis
353+
354+
355+type Location
356+ = Above
357+ | Below
358+ | OnRight
359+ | OnLeft
360+ | InFront
361+ | Behind
362+
363+
364+{-| -}
365+type Color
366+ = Rgba Float Float Float Float
367+
368+
369+type NodeName
370+ = Generic
371+ | NodeName String
372+ | Embedded String String
373+
374+
375+type NearbyChildren msg
376+ = NoNearbyChildren
377+ | ChildrenBehind (List (Html.Html msg))
378+ | ChildrenInFront (List (Html.Html msg))
379+ | ChildrenBehindAndInFront (List (Html.Html msg)) (List (Html.Html msg))
380+
381+
382+div =
383+ Generic
384+
385+
386+type alias Gathered msg =
387+ { node : NodeName
388+ , attributes : List (VirtualDom.Attribute msg)
389+ , styles : List Style
390+ , children : NearbyChildren msg
391+ , has : Flag.Field
392+ }
393+
394+
395+htmlClass : String -> Attribute aligned msg
396+htmlClass cls =
397+ Attr <| Html.Attributes.class cls
398+
399+
400+{-| -}
401+unstyled : VirtualDom.Node msg -> Element msg
402+unstyled =
403+ Unstyled << always
404+
405+
406+finalizeNode has node attributes children embedMode parentContext =
407+ let
408+ createNode nodeName attrs =
409+ case children of
410+ Keyed keyed ->
411+ VirtualDom.keyedNode nodeName
412+ attrs
413+ (case embedMode of
414+ NoStyleSheet ->
415+ keyed
416+
417+ OnlyDynamic opts styles ->
418+ embedKeyed False opts styles keyed
419+
420+ StaticRootAndDynamic opts styles ->
421+ embedKeyed True opts styles keyed
422+ )
423+
424+ Unkeyed unkeyed ->
425+ (case nodeName of
426+ "div" ->
427+ Html.div
428+
429+ "p" ->
430+ Html.p
431+
432+ _ ->
433+ VirtualDom.node nodeName
434+ )
435+ attrs
436+ (case embedMode of
437+ NoStyleSheet ->
438+ unkeyed
439+
440+ OnlyDynamic opts styles ->
441+ embedWith False opts styles unkeyed
442+
443+ StaticRootAndDynamic opts styles ->
444+ embedWith True opts styles unkeyed
445+ )
446+
447+ html =
448+ case node of
449+ Generic ->
450+ createNode "div" attributes
451+
452+ NodeName nodeName ->
453+ createNode nodeName attributes
454+
455+ Embedded nodeName internal ->
456+ VirtualDom.node nodeName
457+ attributes
458+ [ createNode internal
459+ [ Html.Attributes.class
460+ (classes.any ++ " " ++ classes.single)
461+ ]
462+ ]
463+ in
464+ case parentContext of
465+ AsRow ->
466+ if Flag.present Flag.widthFill has && not (Flag.present Flag.widthBetween has) then
467+ html
468+
469+ else if Flag.present Flag.alignRight has then
470+ Html.u
471+ [ Html.Attributes.class
472+ (String.join " "
473+ [ classes.any
474+ , classes.single
475+ , classes.container
476+ , classes.contentCenterY
477+ , classes.alignContainerRight
478+ ]
479+ )
480+ ]
481+ [ html ]
482+
483+ else if Flag.present Flag.centerX has then
484+ Html.s
485+ [ Html.Attributes.class
486+ (String.join " "
487+ [ classes.any
488+ , classes.single
489+ , classes.container
490+ , classes.contentCenterY
491+ , classes.alignContainerCenterX
492+ ]
493+ )
494+ ]
495+ [ html ]
496+
497+ else
498+ html
499+
500+ AsColumn ->
501+ if Flag.present Flag.heightFill has && not (Flag.present Flag.heightBetween has) then
502+ html
503+
504+ else if Flag.present Flag.centerY has then
505+ Html.s
506+ [ Html.Attributes.class
507+ (String.join " "
508+ [ classes.any
509+ , classes.single
510+ , classes.container
511+ , classes.alignContainerCenterY
512+ ]
513+ )
514+ ]
515+ [ html ]
516+
517+ else if Flag.present Flag.alignBottom has then
518+ Html.u
519+ [ Html.Attributes.class
520+ (String.join " "
521+ [ classes.any
522+ , classes.single
523+ , classes.container
524+ , classes.alignContainerBottom
525+ ]
526+ )
527+ ]
528+ [ html ]
529+
530+ else
531+ html
532+
533+ _ ->
534+ html
535+
536+
537+embedWith static opts styles children =
538+ let
539+ dynamicStyleSheet =
540+ styles
541+ |> List.foldl reduceStyles ( Set.empty, renderFocusStyle opts.focus )
542+ |> Tuple.second
543+ -- |> reduceStylesRecursive Set.empty [ ]) --renderFocusStyle opts.focus ]
544+ -- |> sortedReduce
545+ |> toStyleSheet opts
546+ in
547+ if static then
548+ staticRoot opts
549+ :: dynamicStyleSheet
550+ :: children
551+
552+ else
553+ dynamicStyleSheet
554+ :: children
555+
556+
557+embedKeyed static opts styles children =
558+ let
559+ dynamicStyleSheet =
560+ styles
561+ |> List.foldl reduceStyles ( Set.empty, renderFocusStyle opts.focus )
562+ |> Tuple.second
563+ -- |> reduceStylesRecursive Set.empty [ ]) --renderFocusStyle opts.focus ]
564+ -- |> sortedReduce
565+ |> toStyleSheet opts
566+ in
567+ if static then
568+ ( "static-stylesheet", staticRoot opts )
569+ :: ( "dynamic-stylesheet"
570+ , dynamicStyleSheet
571+ )
572+ :: children
573+
574+ else
575+ ( "dynamic-stylesheet"
576+ , dynamicStyleSheet
577+ )
578+ :: children
579+
580+
581+reduceStylesRecursive : Set String -> List Style -> List Style -> List Style
582+reduceStylesRecursive cache found styles =
583+ case styles of
584+ [] ->
585+ found
586+
587+ head :: remaining ->
588+ let
589+ styleName =
590+ getStyleName head
591+ in
592+ if Set.member styleName cache then
593+ reduceStylesRecursive cache found remaining
594+
595+ else
596+ reduceStylesRecursive (Set.insert styleName cache) (head :: found) remaining
597+
598+
599+reduceStyles : Style -> ( Set String, List Style ) -> ( Set String, List Style )
600+reduceStyles style (( cache, existing ) as nevermind) =
601+ let
602+ styleName =
603+ getStyleName style
604+ in
605+ if Set.member styleName cache then
606+ nevermind
607+
608+ else
609+ ( Set.insert styleName cache
610+ , style :: existing
611+ )
612+
613+
614+sortedReduce styles =
615+ styles
616+ -- |> List.map (\x -> ( getStyleName x, x ))
617+ |> List.sortBy getStyleName
618+ |> reduceRecursiveCalcName []
619+
620+
621+reduceRecursiveCalcName : List Style -> List Style -> List Style
622+reduceRecursiveCalcName found styles =
623+ case styles of
624+ [] ->
625+ found
626+
627+ headOfList :: [] ->
628+ headOfList :: found
629+
630+ headOfList :: other :: remaining ->
631+ if headOfList /= other then
632+ reduceRecursiveCalcName (headOfList :: found) (other :: remaining)
633+
634+ else
635+ reduceRecursiveCalcName found (other :: remaining)
636+
637+
638+reduceRecursive : List Style -> List ( String, Style ) -> List Style
639+reduceRecursive found styles =
640+ case styles of
641+ [] ->
642+ found
643+
644+ ( _, headOfList ) :: [] ->
645+ headOfList :: found
646+
647+ ( headOfListName, headOfList ) :: ( otherName, other ) :: remaining ->
648+ if headOfListName /= otherName then
649+ reduceRecursive (headOfList :: found) (( otherName, other ) :: remaining)
650+
651+ else
652+ reduceRecursive found (( otherName, other ) :: remaining)
653+
654+
655+addNodeName : String -> NodeName -> NodeName
656+addNodeName newNode old =
657+ case old of
658+ Generic ->
659+ NodeName newNode
660+
661+ NodeName name ->
662+ Embedded name newNode
663+
664+ Embedded x y ->
665+ Embedded x y
666+
667+
668+alignXName : HAlign -> String
669+alignXName align =
670+ case align of
671+ Left ->
672+ classes.alignedHorizontally ++ " " ++ classes.alignLeft
673+
674+ Right ->
675+ classes.alignedHorizontally ++ " " ++ classes.alignRight
676+
677+ CenterX ->
678+ classes.alignedHorizontally ++ " " ++ classes.alignCenterX
679+
680+
681+alignYName : VAlign -> String
682+alignYName align =
683+ case align of
684+ Top ->
685+ classes.alignedVertically ++ " " ++ classes.alignTop
686+
687+ Bottom ->
688+ classes.alignedVertically ++ " " ++ classes.alignBottom
689+
690+ CenterY ->
691+ classes.alignedVertically ++ " " ++ classes.alignCenterY
692+
693+
694+transformClass transform =
695+ case transform of
696+ Untransformed ->
697+ Nothing
698+
699+ Moved ( x, y, z ) ->
700+ Just <|
701+ "mv-"
702+ ++ floatClass x
703+ ++ "-"
704+ ++ floatClass y
705+ ++ "-"
706+ ++ floatClass z
707+
708+ FullTransform ( tx, ty, tz ) ( sx, sy, sz ) ( ox, oy, oz ) angle ->
709+ Just <|
710+ "tfrm-"
711+ ++ floatClass tx
712+ ++ "-"
713+ ++ floatClass ty
714+ ++ "-"
715+ ++ floatClass tz
716+ ++ "-"
717+ ++ floatClass sx
718+ ++ "-"
719+ ++ floatClass sy
720+ ++ "-"
721+ ++ floatClass sz
722+ ++ "-"
723+ ++ floatClass ox
724+ ++ "-"
725+ ++ floatClass oy
726+ ++ "-"
727+ ++ floatClass oz
728+ ++ "-"
729+ ++ floatClass angle
730+
731+
732+transformValue transform =
733+ case transform of
734+ Untransformed ->
735+ Nothing
736+
737+ Moved ( x, y, z ) ->
738+ Just <|
739+ "translate3d("
740+ ++ String.fromFloat x
741+ ++ "px, "
742+ ++ String.fromFloat y
743+ ++ "px, "
744+ ++ String.fromFloat z
745+ ++ "px)"
746+
747+ FullTransform ( tx, ty, tz ) ( sx, sy, sz ) ( ox, oy, oz ) angle ->
748+ let
749+ translate =
750+ "translate3d("
751+ ++ String.fromFloat tx
752+ ++ "px, "
753+ ++ String.fromFloat ty
754+ ++ "px, "
755+ ++ String.fromFloat tz
756+ ++ "px)"
757+
758+ scale =
759+ "scale3d("
760+ ++ String.fromFloat sx
761+ ++ ", "
762+ ++ String.fromFloat sy
763+ ++ ", "
764+ ++ String.fromFloat sz
765+ ++ ")"
766+
767+ rotate =
768+ "rotate3d("
769+ ++ String.fromFloat ox
770+ ++ ", "
771+ ++ String.fromFloat oy
772+ ++ ", "
773+ ++ String.fromFloat oz
774+ ++ ", "
775+ ++ String.fromFloat angle
776+ ++ "rad)"
777+ in
778+ Just <| translate ++ " " ++ scale ++ " " ++ rotate
779+
780+
781+composeTransformation transform component =
782+ case transform of
783+ Untransformed ->
784+ case component of
785+ MoveX x ->
786+ Moved ( x, 0, 0 )
787+
788+ MoveY y ->
789+ Moved ( 0, y, 0 )
790+
791+ MoveZ z ->
792+ Moved ( 0, 0, z )
793+
794+ MoveXYZ xyz ->
795+ Moved xyz
796+
797+ Rotate xyz angle ->
798+ FullTransform ( 0, 0, 0 ) ( 1, 1, 1 ) xyz angle
799+
800+ Scale xyz ->
801+ FullTransform ( 0, 0, 0 ) xyz ( 0, 0, 1 ) 0
802+
803+ Moved (( x, y, z ) as moved) ->
804+ case component of
805+ MoveX newX ->
806+ Moved ( newX, y, z )
807+
808+ MoveY newY ->
809+ Moved ( x, newY, z )
810+
811+ MoveZ newZ ->
812+ Moved ( x, y, newZ )
813+
814+ MoveXYZ xyz ->
815+ Moved xyz
816+
817+ Rotate xyz angle ->
818+ FullTransform moved ( 1, 1, 1 ) xyz angle
819+
820+ Scale scale ->
821+ FullTransform moved scale ( 0, 0, 1 ) 0
822+
823+ FullTransform (( x, y, z ) as moved) scaled origin angle ->
824+ case component of
825+ MoveX newX ->
826+ FullTransform ( newX, y, z ) scaled origin angle
827+
828+ MoveY newY ->
829+ FullTransform ( x, newY, z ) scaled origin angle
830+
831+ MoveZ newZ ->
832+ FullTransform ( x, y, newZ ) scaled origin angle
833+
834+ MoveXYZ newMove ->
835+ FullTransform newMove scaled origin angle
836+
837+ Rotate newOrigin newAngle ->
838+ FullTransform moved scaled newOrigin newAngle
839+
840+ Scale newScale ->
841+ FullTransform moved newScale origin angle
842+
843+
844+skippable flag style =
845+ if flag == Flag.borderWidth then
846+ case style of
847+ Single _ _ val ->
848+ case val of
849+ "0px" ->
850+ True
851+
852+ "1px" ->
853+ True
854+
855+ "2px" ->
856+ True
857+
858+ "3px" ->
859+ True
860+
861+ "4px" ->
862+ True
863+
864+ "5px" ->
865+ True
866+
867+ "6px" ->
868+ True
869+
870+ _ ->
871+ False
872+
873+ _ ->
874+ False
875+
876+ else
877+ case style of
878+ FontSize i ->
879+ i >= 8 && i <= 32
880+
881+ PaddingStyle name t r b l ->
882+ t == b && t == r && t == l && t >= 0 && t <= 24
883+
884+ -- SpacingStyle _ _ _ ->
885+ -- True
886+ -- FontFamily _ _ ->
887+ -- True
888+ _ ->
889+ False
890+
891+
892+gatherAttrRecursive :
893+ String
894+ -> NodeName
895+ -> Flag.Field
896+ -> Transformation
897+ -> List Style
898+ -> List (VirtualDom.Attribute msg)
899+ -> NearbyChildren msg
900+ -> List (Attribute aligned msg)
901+ -> Gathered msg
902+gatherAttrRecursive classes node has transform styles attrs children elementAttrs =
903+ case elementAttrs of
904+ [] ->
905+ case transformClass transform of
906+ Nothing ->
907+ { attributes = Html.Attributes.class classes :: attrs
908+ , styles = styles
909+ , node = node
910+ , children = children
911+ , has = has
912+ }
913+
914+ Just class ->
915+ { attributes = Html.Attributes.class (classes ++ " " ++ class) :: attrs
916+ , styles = Transform transform :: styles
917+ , node = node
918+ , children = children
919+ , has = has
920+ }
921+
922+ attribute :: remaining ->
923+ case attribute of
924+ NoAttribute ->
925+ gatherAttrRecursive classes node has transform styles attrs children remaining
926+
927+ Class flag exactClassName ->
928+ if Flag.present flag has then
929+ gatherAttrRecursive classes node has transform styles attrs children remaining
930+
931+ else
932+ gatherAttrRecursive (exactClassName ++ " " ++ classes) node (Flag.add flag has) transform styles attrs children remaining
933+
934+ Attr actualAttribute ->
935+ gatherAttrRecursive classes node has transform styles (actualAttribute :: attrs) children remaining
936+
937+ StyleClass flag style ->
938+ if Flag.present flag has then
939+ gatherAttrRecursive classes node has transform styles attrs children remaining
940+
941+ else if skippable flag style then
942+ gatherAttrRecursive (getStyleName style ++ " " ++ classes)
943+ node
944+ (Flag.add flag has)
945+ transform
946+ styles
947+ attrs
948+ children
949+ remaining
950+
951+ else
952+ gatherAttrRecursive (getStyleName style ++ " " ++ classes)
953+ node
954+ (Flag.add flag has)
955+ transform
956+ (style :: styles)
957+ attrs
958+ children
959+ remaining
960+
961+ TransformComponent flag component ->
962+ gatherAttrRecursive classes
963+ node
964+ (Flag.add flag has)
965+ (composeTransformation transform component)
966+ styles
967+ attrs
968+ children
969+ remaining
970+
971+ Width width ->
972+ if Flag.present Flag.width has then
973+ gatherAttrRecursive classes node has transform styles attrs children remaining
974+
975+ else
976+ case width of
977+ Px px ->
978+ gatherAttrRecursive ((Internal.Style.classes.widthExact ++ " width-px-" ++ String.fromInt px) ++ " " ++ classes)
979+ node
980+ (Flag.add Flag.width has)
981+ transform
982+ (Single ("width-px-" ++ String.fromInt px) "width" (String.fromInt px ++ "px") :: styles)
983+ attrs
984+ children
985+ remaining
986+
987+ Content ->
988+ gatherAttrRecursive (classes ++ " " ++ Internal.Style.classes.widthContent)
989+ node
990+ (Flag.add Flag.widthContent (Flag.add Flag.width has))
991+ transform
992+ styles
993+ attrs
994+ children
995+ remaining
996+
997+ Fill portion ->
998+ if portion == 1 then
999+ gatherAttrRecursive (classes ++ " " ++ Internal.Style.classes.widthFill)
1000+ node
1001+ (Flag.add Flag.widthFill (Flag.add Flag.width has))
1002+ transform
1003+ styles
1004+ attrs
1005+ children
1006+ remaining
1007+
1008+ else
1009+ gatherAttrRecursive (classes ++ " " ++ Internal.Style.classes.widthFillPortion ++ " width-fill-" ++ String.fromInt portion)
1010+ node
1011+ (Flag.add Flag.widthFill (Flag.add Flag.width has))
1012+ transform
1013+ (Single
1014+ (Internal.Style.classes.any
1015+ ++ "."
1016+ ++ Internal.Style.classes.row
1017+ ++ " > "
1018+ ++ (Internal.Style.dot <| "width-fill-" ++ String.fromInt portion)
1019+ )
1020+ "flex-grow"
1021+ (String.fromInt (portion * 100000))
1022+ :: styles
1023+ )
1024+ attrs
1025+ children
1026+ remaining
1027+
1028+ _ ->
1029+ let
1030+ ( addToFlags, newClass, newStyles ) =
1031+ renderWidth width
1032+ in
1033+ gatherAttrRecursive (classes ++ " " ++ newClass)
1034+ node
1035+ (Flag.merge addToFlags (Flag.add Flag.width has))
1036+ transform
1037+ (newStyles ++ styles)
1038+ attrs
1039+ children
1040+ remaining
1041+
1042+ Height height ->
1043+ if Flag.present Flag.height has then
1044+ gatherAttrRecursive classes node has transform styles attrs children remaining
1045+
1046+ else
1047+ case height of
1048+ Px px ->
1049+ let
1050+ val =
1051+ String.fromInt px ++ "px"
1052+
1053+ name =
1054+ "height-px-" ++ val
1055+ in
1056+ gatherAttrRecursive (Internal.Style.classes.heightExact ++ " " ++ name ++ " " ++ classes)
1057+ node
1058+ (Flag.add Flag.height has)
1059+ transform
1060+ (Single name "height " val :: styles)
1061+ attrs
1062+ children
1063+ remaining
1064+
1065+ Content ->
1066+ gatherAttrRecursive (Internal.Style.classes.heightContent ++ " " ++ classes)
1067+ node
1068+ (Flag.add Flag.heightContent (Flag.add Flag.height has))
1069+ transform
1070+ styles
1071+ attrs
1072+ children
1073+ remaining
1074+
1075+ Fill portion ->
1076+ if portion == 1 then
1077+ gatherAttrRecursive (Internal.Style.classes.heightFill ++ " " ++ classes)
1078+ node
1079+ (Flag.add Flag.heightFill (Flag.add Flag.height has))
1080+ transform
1081+ styles
1082+ attrs
1083+ children
1084+ remaining
1085+
1086+ else
1087+ gatherAttrRecursive (classes ++ " " ++ (Internal.Style.classes.heightFillPortion ++ " height-fill-" ++ String.fromInt portion))
1088+ node
1089+ (Flag.add Flag.heightFill (Flag.add Flag.height has))
1090+ transform
1091+ (Single
1092+ (Internal.Style.classes.any
1093+ ++ "."
1094+ ++ Internal.Style.classes.column
1095+ ++ " > "
1096+ ++ (Internal.Style.dot <| "height-fill-" ++ String.fromInt portion)
1097+ )
1098+ "flex-grow"
1099+ (String.fromInt (portion * 100000))
1100+ :: styles
1101+ )
1102+ attrs
1103+ children
1104+ remaining
1105+
1106+ _ ->
1107+ let
1108+ ( addToFlags, newClass, newStyles ) =
1109+ renderHeight height
1110+ in
1111+ gatherAttrRecursive (classes ++ " " ++ newClass)
1112+ node
1113+ (Flag.merge addToFlags (Flag.add Flag.height has))
1114+ transform
1115+ (newStyles ++ styles)
1116+ attrs
1117+ children
1118+ remaining
1119+
1120+ Describe description ->
1121+ case description of
1122+ Main ->
1123+ gatherAttrRecursive classes (addNodeName "main" node) has transform styles attrs children remaining
1124+
1125+ Navigation ->
1126+ gatherAttrRecursive classes (addNodeName "nav" node) has transform styles attrs children remaining
1127+
1128+ ContentInfo ->
1129+ gatherAttrRecursive classes (addNodeName "footer" node) has transform styles attrs children remaining
1130+
1131+ Complementary ->
1132+ gatherAttrRecursive classes (addNodeName "aside" node) has transform styles attrs children remaining
1133+
1134+ Heading i ->
1135+ if i <= 1 then
1136+ gatherAttrRecursive classes (addNodeName "h1" node) has transform styles attrs children remaining
1137+
1138+ else if i < 7 then
1139+ gatherAttrRecursive classes (addNodeName ("h" ++ String.fromInt i) node) has transform styles attrs children remaining
1140+
1141+ else
1142+ gatherAttrRecursive classes (addNodeName "h6" node) has transform styles attrs children remaining
1143+
1144+ Paragraph ->
1145+ -- previously we rendered a <p> tag, though apparently this invalidates the html if it has <div>s inside.
1146+ -- Since we can't guaranteee that there are no divs, we need another strategy.
1147+ -- While it's not documented in many places, there apparently is a paragraph aria role
1148+ -- https://github.com/w3c/aria/blob/11f85f41a5b621fdbe85fc9bcdcd270e653a48ba/common/script/roleInfo.js
1149+ -- Though we'll need to wait till it gets released in an official wai-aria spec to use it.
1150+ -- If it's used at the moment, then Lighthouse complains (likely rightfully) that role paragraph is not recognized.
1151+ gatherAttrRecursive
1152+ classes
1153+ node
1154+ has
1155+ transform
1156+ styles
1157+ attrs
1158+ children
1159+ remaining
1160+
1161+ Button ->
1162+ gatherAttrRecursive classes node has transform styles (VirtualDom.attribute "role" "button" :: attrs) children remaining
1163+
1164+ Label label ->
1165+ gatherAttrRecursive classes node has transform styles (VirtualDom.attribute "aria-label" label :: attrs) children remaining
1166+
1167+ LivePolite ->
1168+ gatherAttrRecursive classes node has transform styles (VirtualDom.attribute "aria-live" "polite" :: attrs) children remaining
1169+
1170+ LiveAssertive ->
1171+ gatherAttrRecursive classes node has transform styles (VirtualDom.attribute "aria-live" "assertive" :: attrs) children remaining
1172+
1173+ Nearby location elem ->
1174+ let
1175+ newStyles =
1176+ case elem of
1177+ Empty ->
1178+ styles
1179+
1180+ Text str ->
1181+ styles
1182+
1183+ Unstyled html ->
1184+ styles
1185+
1186+ Styled styled ->
1187+ styles ++ styled.styles
1188+ in
1189+ gatherAttrRecursive
1190+ classes
1191+ node
1192+ has
1193+ transform
1194+ newStyles
1195+ attrs
1196+ (addNearbyElement location elem children)
1197+ remaining
1198+
1199+ AlignX x ->
1200+ if Flag.present Flag.xAlign has then
1201+ gatherAttrRecursive classes node has transform styles attrs children remaining
1202+
1203+ else
1204+ gatherAttrRecursive (alignXName x ++ " " ++ classes)
1205+ node
1206+ (has
1207+ |> Flag.add Flag.xAlign
1208+ |> (\flags ->
1209+ case x of
1210+ CenterX ->
1211+ Flag.add Flag.centerX flags
1212+
1213+ Right ->
1214+ Flag.add Flag.alignRight flags
1215+
1216+ _ ->
1217+ flags
1218+ )
1219+ )
1220+ transform
1221+ styles
1222+ attrs
1223+ children
1224+ remaining
1225+
1226+ AlignY y ->
1227+ if Flag.present Flag.yAlign has then
1228+ gatherAttrRecursive classes node has transform styles attrs children remaining
1229+
1230+ else
1231+ gatherAttrRecursive (alignYName y ++ " " ++ classes)
1232+ node
1233+ (Flag.add Flag.yAlign has
1234+ |> (\flags ->
1235+ case y of
1236+ CenterY ->
1237+ Flag.add Flag.centerY flags
1238+
1239+ Bottom ->
1240+ Flag.add Flag.alignBottom flags
1241+
1242+ _ ->
1243+ flags
1244+ )
1245+ )
1246+ transform
1247+ styles
1248+ attrs
1249+ children
1250+ remaining
1251+
1252+
1253+addNearbyElement location elem existing =
1254+ let
1255+ nearby =
1256+ nearbyElement location elem
1257+ in
1258+ case existing of
1259+ NoNearbyChildren ->
1260+ case location of
1261+ Behind ->
1262+ ChildrenBehind [ nearby ]
1263+
1264+ _ ->
1265+ ChildrenInFront [ nearby ]
1266+
1267+ ChildrenBehind existingBehind ->
1268+ case location of
1269+ Behind ->
1270+ ChildrenBehind (nearby :: existingBehind)
1271+
1272+ _ ->
1273+ ChildrenBehindAndInFront existingBehind [ nearby ]
1274+
1275+ ChildrenInFront existingInFront ->
1276+ case location of
1277+ Behind ->
1278+ ChildrenBehindAndInFront [ nearby ] existingInFront
1279+
1280+ _ ->
1281+ ChildrenInFront (nearby :: existingInFront)
1282+
1283+ ChildrenBehindAndInFront existingBehind existingInFront ->
1284+ case location of
1285+ Behind ->
1286+ ChildrenBehindAndInFront (nearby :: existingBehind) existingInFront
1287+
1288+ _ ->
1289+ ChildrenBehindAndInFront existingBehind (nearby :: existingInFront)
1290+
1291+
1292+nearbyElement location elem =
1293+ Html.div
1294+ [ Html.Attributes.class <|
1295+ case location of
1296+ Above ->
1297+ String.join " "
1298+ [ Internal.Style.classes.nearby
1299+ , Internal.Style.classes.single
1300+ , Internal.Style.classes.above
1301+ ]
1302+
1303+ Below ->
1304+ String.join " "
1305+ [ Internal.Style.classes.nearby
1306+ , Internal.Style.classes.single
1307+ , Internal.Style.classes.below
1308+ ]
1309+
1310+ OnRight ->
1311+ String.join " "
1312+ [ Internal.Style.classes.nearby
1313+ , Internal.Style.classes.single
1314+ , Internal.Style.classes.onRight
1315+ ]
1316+
1317+ OnLeft ->
1318+ String.join " "
1319+ [ Internal.Style.classes.nearby
1320+ , Internal.Style.classes.single
1321+ , Internal.Style.classes.onLeft
1322+ ]
1323+
1324+ InFront ->
1325+ String.join " "
1326+ [ Internal.Style.classes.nearby
1327+ , Internal.Style.classes.single
1328+ , Internal.Style.classes.inFront
1329+ ]
1330+
1331+ Behind ->
1332+ String.join " "
1333+ [ Internal.Style.classes.nearby
1334+ , Internal.Style.classes.single
1335+ , Internal.Style.classes.behind
1336+ ]
1337+ ]
1338+ [ case elem of
1339+ Empty ->
1340+ VirtualDom.text ""
1341+
1342+ Text str ->
1343+ textElement str
1344+
1345+ Unstyled html ->
1346+ html asEl
1347+
1348+ Styled styled ->
1349+ styled.html NoStyleSheet asEl
1350+ ]
1351+
1352+
1353+renderWidth w =
1354+ case w of
1355+ Px px ->
1356+ ( Flag.none
1357+ , Internal.Style.classes.widthExact ++ " width-px-" ++ String.fromInt px
1358+ , [ Single ("width-px-" ++ String.fromInt px) "width" (String.fromInt px ++ "px") ]
1359+ )
1360+
1361+ Content ->
1362+ ( Flag.add Flag.widthContent Flag.none
1363+ , Internal.Style.classes.widthContent
1364+ , []
1365+ )
1366+
1367+ Fill portion ->
1368+ if portion == 1 then
1369+ ( Flag.add Flag.widthFill Flag.none
1370+ , Internal.Style.classes.widthFill
1371+ , []
1372+ )
1373+
1374+ else
1375+ ( Flag.add Flag.widthFill Flag.none
1376+ , Internal.Style.classes.widthFillPortion ++ " width-fill-" ++ String.fromInt portion
1377+ , [ Single
1378+ (Internal.Style.classes.any
1379+ ++ "."
1380+ ++ Internal.Style.classes.row
1381+ ++ " > "
1382+ ++ (Internal.Style.dot <| "width-fill-" ++ String.fromInt portion)
1383+ )
1384+ "flex-grow"
1385+ (String.fromInt (portion * 100000))
1386+ ]
1387+ )
1388+
1389+ Min minSize len ->
1390+ let
1391+ cls =
1392+ "min-width-"
1393+ ++ String.fromInt minSize
1394+
1395+ style =
1396+ Single
1397+ cls
1398+ "min-width"
1399+ (String.fromInt minSize ++ "px")
1400+
1401+ ( newFlag, newAttrs, newStyle ) =
1402+ renderWidth len
1403+ in
1404+ ( Flag.add Flag.widthBetween newFlag
1405+ , cls ++ " " ++ newAttrs
1406+ , style :: newStyle
1407+ )
1408+
1409+ Max maxSize len ->
1410+ let
1411+ cls =
1412+ "max-width-" ++ String.fromInt maxSize
1413+
1414+ style =
1415+ Single cls
1416+ "max-width"
1417+ (String.fromInt maxSize ++ "px")
1418+
1419+ ( newFlag, newAttrs, newStyle ) =
1420+ renderWidth len
1421+ in
1422+ ( Flag.add Flag.widthBetween newFlag
1423+ , cls ++ " " ++ newAttrs
1424+ , style :: newStyle
1425+ )
1426+
1427+
1428+renderHeight h =
1429+ case h of
1430+ Px px ->
1431+ let
1432+ val =
1433+ String.fromInt px
1434+
1435+ name =
1436+ "height-px-" ++ val
1437+ in
1438+ ( Flag.none
1439+ , Internal.Style.classes.heightExact ++ " " ++ name
1440+ , [ Single name "height" (val ++ "px") ]
1441+ )
1442+
1443+ Content ->
1444+ ( Flag.add Flag.heightContent Flag.none
1445+ , Internal.Style.classes.heightContent
1446+ , []
1447+ )
1448+
1449+ Fill portion ->
1450+ if portion == 1 then
1451+ ( Flag.add Flag.heightFill Flag.none
1452+ , Internal.Style.classes.heightFill
1453+ , []
1454+ )
1455+
1456+ else
1457+ ( Flag.add Flag.heightFill Flag.none
1458+ , Internal.Style.classes.heightFillPortion ++ " height-fill-" ++ String.fromInt portion
1459+ , [ Single
1460+ (Internal.Style.classes.any
1461+ ++ "."
1462+ ++ Internal.Style.classes.column
1463+ ++ " > "
1464+ ++ (Internal.Style.dot <| "height-fill-" ++ String.fromInt portion)
1465+ )
1466+ "flex-grow"
1467+ (String.fromInt (portion * 100000))
1468+ ]
1469+ )
1470+
1471+ Min minSize len ->
1472+ let
1473+ cls =
1474+ "min-height-"
1475+ ++ String.fromInt minSize
1476+
1477+ style =
1478+ Single
1479+ cls
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.
1483+ (String.fromInt minSize ++ "px !important")
1484+
1485+ ( newFlag, newAttrs, newStyle ) =
1486+ renderHeight len
1487+ in
1488+ ( Flag.add Flag.heightBetween newFlag
1489+ , cls ++ " " ++ newAttrs
1490+ , style :: newStyle
1491+ )
1492+
1493+ Max maxSize len ->
1494+ let
1495+ cls =
1496+ "max-height-" ++ String.fromInt maxSize
1497+
1498+ style =
1499+ Single cls
1500+ "max-height"
1501+ (String.fromInt maxSize ++ "px")
1502+
1503+ ( newFlag, newAttrs, newStyle ) =
1504+ renderHeight len
1505+ in
1506+ ( Flag.add Flag.heightBetween newFlag
1507+ , cls ++ " " ++ newAttrs
1508+ , style :: newStyle
1509+ )
1510+
1511+
1512+rowClass =
1513+ classes.any ++ " " ++ classes.row
1514+
1515+
1516+columnClass =
1517+ classes.any ++ " " ++ classes.column
1518+
1519+
1520+singleClass =
1521+ classes.any ++ " " ++ classes.single
1522+
1523+
1524+gridClass =
1525+ classes.any ++ " " ++ classes.grid
1526+
1527+
1528+paragraphClass =
1529+ classes.any ++ " " ++ classes.paragraph
1530+
1531+
1532+pageClass =
1533+ classes.any ++ " " ++ classes.page
1534+
1535+
1536+contextClasses context =
1537+ case context of
1538+ AsRow ->
1539+ rowClass
1540+
1541+ AsColumn ->
1542+ columnClass
1543+
1544+ AsEl ->
1545+ singleClass
1546+
1547+ AsGrid ->
1548+ gridClass
1549+
1550+ AsParagraph ->
1551+ paragraphClass
1552+
1553+ AsTextColumn ->
1554+ pageClass
1555+
1556+
1557+element : LayoutContext -> NodeName -> List (Attribute aligned msg) -> Children (Element msg) -> Element msg
1558+element context node attributes children =
1559+ attributes
1560+ |> List.reverse
1561+ |> gatherAttrRecursive (contextClasses context) node Flag.none untransformed [] [] NoNearbyChildren
1562+ |> createElement context children
1563+
1564+
1565+untransformed =
1566+ Untransformed
1567+
1568+
1569+createElement : LayoutContext -> Children (Element msg) -> Gathered msg -> Element msg
1570+createElement context children rendered =
1571+ let
1572+ gather child ( htmls, existingStyles ) =
1573+ case child of
1574+ Unstyled html ->
1575+ if context == asParagraph then
1576+ ( html context :: htmls
1577+ , existingStyles
1578+ )
1579+
1580+ else
1581+ ( html context :: htmls
1582+ , existingStyles
1583+ )
1584+
1585+ Styled styled ->
1586+ if context == asParagraph then
1587+ ( styled.html NoStyleSheet context :: htmls
1588+ , if List.isEmpty existingStyles then
1589+ styled.styles
1590+
1591+ else
1592+ styled.styles ++ existingStyles
1593+ )
1594+
1595+ else
1596+ ( styled.html NoStyleSheet context :: htmls
1597+ , if List.isEmpty existingStyles then
1598+ styled.styles
1599+
1600+ else
1601+ styled.styles ++ existingStyles
1602+ )
1603+
1604+ Text str ->
1605+ -- TEXT OPTIMIZATION
1606+ -- You can have raw text if the element is an el, and has `width-content` and `height-content`
1607+ -- Same if it's a column or row with one child and width-content, height-content
1608+ -- interferes with css grid
1609+ -- Maybe we could unpack text elements in a paragraph as well,
1610+ -- however, embedded elements that are larger than the line height will overlap with exisitng text.
1611+ -- I don't think that's what we want.
1612+ -- if
1613+ -- context
1614+ -- == asEl
1615+ -- || context
1616+ -- == asParagraph
1617+ -- then
1618+ -- ( VirtualDom.text
1619+ -- (if context == asParagraph then
1620+ -- str
1621+ -- else
1622+ -- str
1623+ -- )
1624+ -- :: htmls
1625+ -- , existingStyles
1626+ -- )
1627+ -- else
1628+ ( (if context == asEl then
1629+ textElementFill str
1630+
1631+ else
1632+ textElement str
1633+ )
1634+ :: htmls
1635+ , existingStyles
1636+ )
1637+
1638+ Empty ->
1639+ ( htmls, existingStyles )
1640+
1641+ gatherKeyed ( key, child ) ( htmls, existingStyles ) =
1642+ case child of
1643+ Unstyled html ->
1644+ if context == asParagraph then
1645+ ( ( key, html context ) :: htmls
1646+ , existingStyles
1647+ )
1648+
1649+ else
1650+ ( ( key, html context ) :: htmls
1651+ , existingStyles
1652+ )
1653+
1654+ Styled styled ->
1655+ if context == asParagraph then
1656+ ( ( key, styled.html NoStyleSheet context )
1657+ :: htmls
1658+ , if List.isEmpty existingStyles then
1659+ styled.styles
1660+
1661+ else
1662+ styled.styles ++ existingStyles
1663+ )
1664+
1665+ else
1666+ ( ( key, styled.html NoStyleSheet context ) :: htmls
1667+ , if List.isEmpty existingStyles then
1668+ styled.styles
1669+
1670+ else
1671+ styled.styles ++ existingStyles
1672+ )
1673+
1674+ Text str ->
1675+ -- TEXT OPTIMIZATION
1676+ -- You can have raw text if the element is an el, and has `width-content` and `height-content`
1677+ -- Same if it's a column or row with one child and width-content, height-content
1678+ -- if
1679+ -- context
1680+ -- == asEl
1681+ -- || context
1682+ -- == asParagraph
1683+ -- then
1684+ -- ( ( key
1685+ -- , VirtualDom.text
1686+ -- str
1687+ -- )
1688+ -- :: htmls
1689+ -- , existingStyles
1690+ -- )
1691+ -- else
1692+ ( ( key
1693+ , if context == asEl then
1694+ textElementFill str
1695+
1696+ else
1697+ textElement str
1698+ )
1699+ :: htmls
1700+ , existingStyles
1701+ )
1702+
1703+ Empty ->
1704+ ( htmls, existingStyles )
1705+ in
1706+ case children of
1707+ Keyed keyedChildren ->
1708+ case List.foldr gatherKeyed ( [], [] ) keyedChildren of
1709+ ( keyed, styles ) ->
1710+ let
1711+ newStyles =
1712+ if List.isEmpty styles then
1713+ rendered.styles
1714+
1715+ else
1716+ rendered.styles ++ styles
1717+ in
1718+ case newStyles of
1719+ [] ->
1720+ Unstyled
1721+ (finalizeNode rendered.has
1722+ rendered.node
1723+ rendered.attributes
1724+ (Keyed
1725+ (addKeyedChildren "nearby-element-pls" keyed rendered.children)
1726+ )
1727+ NoStyleSheet
1728+ )
1729+
1730+ allStyles ->
1731+ Styled
1732+ { styles = allStyles
1733+ , html =
1734+ finalizeNode
1735+ rendered.has
1736+ rendered.node
1737+ rendered.attributes
1738+ (Keyed
1739+ (addKeyedChildren "nearby-element-pls" keyed rendered.children)
1740+ )
1741+ }
1742+
1743+ Unkeyed unkeyedChildren ->
1744+ case List.foldr gather ( [], [] ) unkeyedChildren of
1745+ ( unkeyed, styles ) ->
1746+ let
1747+ newStyles =
1748+ if List.isEmpty styles then
1749+ rendered.styles
1750+
1751+ else
1752+ rendered.styles ++ styles
1753+ in
1754+ case newStyles of
1755+ [] ->
1756+ Unstyled
1757+ (finalizeNode
1758+ rendered.has
1759+ rendered.node
1760+ rendered.attributes
1761+ (Unkeyed (addChildren unkeyed rendered.children))
1762+ NoStyleSheet
1763+ )
1764+
1765+ allStyles ->
1766+ Styled
1767+ { styles = allStyles
1768+ , html =
1769+ finalizeNode
1770+ rendered.has
1771+ rendered.node
1772+ rendered.attributes
1773+ (Unkeyed (addChildren unkeyed rendered.children))
1774+ }
1775+
1776+
1777+addChildren existing nearbyChildren =
1778+ case nearbyChildren of
1779+ NoNearbyChildren ->
1780+ existing
1781+
1782+ ChildrenBehind behind ->
1783+ behind ++ existing
1784+
1785+ ChildrenInFront inFront ->
1786+ existing ++ inFront
1787+
1788+ ChildrenBehindAndInFront behind inFront ->
1789+ behind ++ existing ++ inFront
1790+
1791+
1792+addKeyedChildren key existing nearbyChildren =
1793+ case nearbyChildren of
1794+ NoNearbyChildren ->
1795+ existing
1796+
1797+ ChildrenBehind behind ->
1798+ List.map (\x -> ( key, x )) behind ++ existing
1799+
1800+ ChildrenInFront inFront ->
1801+ existing ++ List.map (\x -> ( key, x )) inFront
1802+
1803+ ChildrenBehindAndInFront behind inFront ->
1804+ List.map (\x -> ( key, x )) behind
1805+ ++ existing
1806+ ++ List.map (\x -> ( key, x )) inFront
1807+
1808+
1809+unit =
1810+ 0
1811+
1812+
1813+defaultOptions =
1814+ { hover = AllowHover
1815+ , focus = focusDefaultStyle
1816+ , mode = Layout
1817+ }
1818+
1819+
1820+staticRoot : OptionRecord -> VirtualDom.Node msg
1821+staticRoot opts =
1822+ case opts.mode of
1823+ Layout ->
1824+ -- wrap the style node in a div to prevent `Dark Reader` from blowin up the dom.
1825+ VirtualDom.node "div"
1826+ []
1827+ [ VirtualDom.node "style" [] [ VirtualDom.text Internal.Style.rules ] ]
1828+
1829+ NoStaticStyleSheet ->
1830+ VirtualDom.text ""
1831+
1832+ WithVirtualCss ->
1833+ VirtualDom.node "elm-ui-static-rules" [ VirtualDom.property "rules" (Encode.string Internal.Style.rules) ] []
1834+
1835+
1836+addWhen ifThis x to =
1837+ if ifThis then
1838+ x :: to
1839+
1840+ else
1841+ to
1842+
1843+
1844+{-| TODO:
1845+
1846+This doesn't reduce equivalent attributes completely.
1847+
1848+-}
1849+filter : List (Attribute aligned msg) -> List (Attribute aligned msg)
1850+filter attrs =
1851+ Tuple.first <|
1852+ List.foldr
1853+ (\x ( found, has ) ->
1854+ case x of
1855+ NoAttribute ->
1856+ ( found, has )
1857+
1858+ Class key _ ->
1859+ ( x :: found, has )
1860+
1861+ Attr attr ->
1862+ ( x :: found, has )
1863+
1864+ StyleClass _ style ->
1865+ ( x :: found, has )
1866+
1867+ Width width ->
1868+ if Set.member "width" has then
1869+ ( found, has )
1870+
1871+ else
1872+ ( x :: found, Set.insert "width" has )
1873+
1874+ Height height ->
1875+ if Set.member "height" has then
1876+ ( found, has )
1877+
1878+ else
1879+ ( x :: found, Set.insert "height" has )
1880+
1881+ Describe description ->
1882+ if Set.member "described" has then
1883+ ( found, has )
1884+
1885+ else
1886+ ( x :: found, Set.insert "described" has )
1887+
1888+ Nearby location elem ->
1889+ ( x :: found, has )
1890+
1891+ AlignX _ ->
1892+ if Set.member "align-x" has then
1893+ ( found, has )
1894+
1895+ else
1896+ ( x :: found, Set.insert "align-x" has )
1897+
1898+ AlignY _ ->
1899+ if Set.member "align-y" has then
1900+ ( found, has )
1901+
1902+ else
1903+ ( x :: found, Set.insert "align-y" has )
1904+
1905+ TransformComponent _ _ ->
1906+ if Set.member "transform" has then
1907+ ( found, has )
1908+
1909+ else
1910+ ( x :: found, Set.insert "transform" has )
1911+ )
1912+ ( [], Set.empty )
1913+ attrs
1914+
1915+
1916+isContent len =
1917+ case len of
1918+ Content ->
1919+ True
1920+
1921+ Max _ l ->
1922+ isContent l
1923+
1924+ Min _ l ->
1925+ isContent l
1926+
1927+ _ ->
1928+ False
1929+
1930+
1931+get : List (Attribute aligned msg) -> (Attribute aligned msg -> Bool) -> List (Attribute aligned msg)
1932+get attrs isAttr =
1933+ attrs
1934+ |> filter
1935+ |> List.foldr
1936+ (\x found ->
1937+ if isAttr x then
1938+ x :: found
1939+
1940+ else
1941+ found
1942+ )
1943+ []
1944+
1945+
1946+type Spacing
1947+ = Spaced String Int Int
1948+
1949+
1950+type Padding
1951+ = Padding String Float Float Float Float
1952+
1953+
1954+extractSpacingAndPadding : List (Attribute aligned msg) -> ( Maybe Padding, Maybe Spacing )
1955+extractSpacingAndPadding attrs =
1956+ List.foldr
1957+ (\attr ( pad, spacing ) ->
1958+ ( case pad of
1959+ Just x ->
1960+ pad
1961+
1962+ Nothing ->
1963+ case attr of
1964+ StyleClass _ (PaddingStyle name t r b l) ->
1965+ Just (Padding name t r b l)
1966+
1967+ _ ->
1968+ Nothing
1969+ , case spacing of
1970+ Just x ->
1971+ spacing
1972+
1973+ Nothing ->
1974+ case attr of
1975+ StyleClass _ (SpacingStyle name x y) ->
1976+ Just (Spaced name x y)
1977+
1978+ _ ->
1979+ Nothing
1980+ )
1981+ )
1982+ ( Nothing, Nothing )
1983+ attrs
1984+
1985+
1986+getSpacing : List (Attribute aligned msg) -> ( Int, Int ) -> ( Int, Int )
1987+getSpacing attrs default =
1988+ attrs
1989+ |> List.foldr
1990+ (\attr acc ->
1991+ case acc of
1992+ Just x ->
1993+ Just x
1994+
1995+ Nothing ->
1996+ case attr of
1997+ StyleClass _ (SpacingStyle _ x y) ->
1998+ Just ( x, y )
1999+
2000+ _ ->
2001+ Nothing
2002+ )
2003+ Nothing
2004+ |> Maybe.withDefault default
2005+
2006+
2007+getWidth : List (Attribute aligned msg) -> Maybe Length
2008+getWidth attrs =
2009+ attrs
2010+ |> List.foldr
2011+ (\attr acc ->
2012+ case acc of
2013+ Just x ->
2014+ Just x
2015+
2016+ Nothing ->
2017+ case attr of
2018+ Width len ->
2019+ Just len
2020+
2021+ _ ->
2022+ Nothing
2023+ )
2024+ Nothing
2025+
2026+
2027+getHeight : List (Attribute aligned msg) -> Maybe Length
2028+getHeight attrs =
2029+ attrs
2030+ |> List.foldr
2031+ (\attr acc ->
2032+ case acc of
2033+ Just x ->
2034+ Just x
2035+
2036+ Nothing ->
2037+ case attr of
2038+ Height len ->
2039+ Just len
2040+
2041+ _ ->
2042+ Nothing
2043+ )
2044+ Nothing
2045+
2046+
2047+textElementClasses : String
2048+textElementClasses =
2049+ classes.any
2050+ ++ " "
2051+ ++ classes.text
2052+ ++ " "
2053+ ++ classes.widthContent
2054+ ++ " "
2055+ ++ classes.heightContent
2056+
2057+
2058+textElement : String -> VirtualDom.Node msg
2059+textElement str =
2060+ Html.div
2061+ [ Html.Attributes.class
2062+ textElementClasses
2063+ ]
2064+ [ Html.text str ]
2065+
2066+
2067+textElementFillClasses : String
2068+textElementFillClasses =
2069+ classes.any
2070+ ++ " "
2071+ ++ classes.text
2072+ ++ " "
2073+ ++ classes.widthFill
2074+ ++ " "
2075+ ++ classes.heightFill
2076+
2077+
2078+textElementFill : String -> VirtualDom.Node msg
2079+textElementFill str =
2080+ Html.div
2081+ [ Html.Attributes.class
2082+ textElementFillClasses
2083+ ]
2084+ [ Html.text str ]
2085+
2086+
2087+type Children x
2088+ = Unkeyed (List x)
2089+ | Keyed (List ( String, x ))
2090+
2091+
2092+toHtml mode el =
2093+ case el of
2094+ Unstyled html ->
2095+ html asEl
2096+
2097+ Styled { styles, html } ->
2098+ html (mode styles) asEl
2099+
2100+ Text text ->
2101+ textElement text
2102+
2103+ Empty ->
2104+ textElement ""
2105+
2106+
2107+{-| -}
2108+renderRoot : List Option -> List (Attribute aligned msg) -> Element msg -> VirtualDom.Node msg
2109+renderRoot optionList attributes child =
2110+ let
2111+ options =
2112+ optionsToRecord optionList
2113+
2114+ embedStyle =
2115+ case options.mode of
2116+ NoStaticStyleSheet ->
2117+ OnlyDynamic options
2118+
2119+ _ ->
2120+ StaticRootAndDynamic options
2121+ in
2122+ element asEl div attributes (Unkeyed [ child ])
2123+ |> toHtml embedStyle
2124+
2125+
2126+type RenderMode
2127+ = Layout
2128+ | NoStaticStyleSheet
2129+ | WithVirtualCss
2130+
2131+
2132+type alias OptionRecord =
2133+ { hover : HoverSetting
2134+ , focus : FocusStyle
2135+ , mode : RenderMode
2136+ }
2137+
2138+
2139+type HoverSetting
2140+ = NoHover
2141+ | AllowHover
2142+ | ForceHover
2143+
2144+
2145+type Option
2146+ = HoverOption HoverSetting
2147+ | FocusStyleOption FocusStyle
2148+ | RenderModeOption RenderMode
2149+
2150+
2151+type alias FocusStyle =
2152+ { borderColor : Maybe Color
2153+ , shadow : Maybe Shadow
2154+ , backgroundColor : Maybe Color
2155+ }
2156+
2157+
2158+type alias Shadow =
2159+ { color : Color
2160+ , offset : ( Int, Int )
2161+ , blur : Int
2162+ , size : Int
2163+ }
2164+
2165+
2166+rootStyle : List (Attribute aligned msg)
2167+rootStyle =
2168+ let
2169+ families =
2170+ [ Typeface "Open Sans"
2171+ , Typeface "Helvetica"
2172+ , Typeface "Verdana"
2173+ , SansSerif
2174+ ]
2175+ in
2176+ [ StyleClass Flag.bgColor (Colored ("bg-" ++ formatColorClass (Rgba 1 1 1 0)) "background-color" (Rgba 1 1 1 0))
2177+ , StyleClass Flag.fontColor (Colored ("fc-" ++ formatColorClass (Rgba 0 0 0 1)) "color" (Rgba 0 0 0 1))
2178+ , StyleClass Flag.fontSize (FontSize 20)
2179+ , StyleClass Flag.fontFamily <|
2180+ FontFamily (List.foldl renderFontClassName "font-" families)
2181+ families
2182+ ]
2183+
2184+
2185+renderFontClassName : Font -> String -> String
2186+renderFontClassName font current =
2187+ current
2188+ ++ (case font of
2189+ Serif ->
2190+ "serif"
2191+
2192+ SansSerif ->
2193+ "sans-serif"
2194+
2195+ Monospace ->
2196+ "monospace"
2197+
2198+ Typeface name ->
2199+ name
2200+ |> String.toLower
2201+ |> String.words
2202+ |> String.join "-"
2203+
2204+ ImportFont name url ->
2205+ name
2206+ |> String.toLower
2207+ |> String.words
2208+ |> String.join "-"
2209+
2210+ FontWith { name } ->
2211+ name
2212+ |> String.toLower
2213+ |> String.words
2214+ |> String.join "-"
2215+ )
2216+
2217+
2218+renderFocusStyle :
2219+ FocusStyle
2220+ -> List Style
2221+renderFocusStyle focus =
2222+ [ Style (Internal.Style.dot classes.focusedWithin ++ ":focus-within")
2223+ (List.filterMap identity
2224+ [ Maybe.map (\color -> Property "border-color" (formatColor color)) focus.borderColor
2225+ , Maybe.map (\color -> Property "background-color" (formatColor color)) focus.backgroundColor
2226+ , Maybe.map
2227+ (\shadow ->
2228+ Property "box-shadow"
2229+ (formatBoxShadow
2230+ { color = shadow.color
2231+ , offset =
2232+ shadow.offset
2233+ |> Tuple.mapFirst toFloat
2234+ |> Tuple.mapSecond toFloat
2235+ , inset = False
2236+ , blur =
2237+ toFloat shadow.blur
2238+ , size =
2239+ toFloat shadow.size
2240+ }
2241+ )
2242+ )
2243+ focus.shadow
2244+ , Just <| Property "outline" "none"
2245+ ]
2246+ )
2247+ , Style
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+ )
2252+ (List.filterMap identity
2253+ [ Maybe.map (\color -> Property "border-color" (formatColor color)) focus.borderColor
2254+ , Maybe.map (\color -> Property "background-color" (formatColor color)) focus.backgroundColor
2255+ , Maybe.map
2256+ (\shadow ->
2257+ Property "box-shadow"
2258+ (formatBoxShadow
2259+ { color = shadow.color
2260+ , offset =
2261+ shadow.offset
2262+ |> Tuple.mapFirst toFloat
2263+ |> Tuple.mapSecond toFloat
2264+ , inset = False
2265+ , blur = toFloat shadow.blur
2266+ , size = toFloat shadow.size
2267+ }
2268+ )
2269+ )
2270+ focus.shadow
2271+ , Just <| Property "outline" "none"
2272+ ]
2273+ )
2274+ ]
2275+
2276+
2277+focusDefaultStyle : { backgroundColor : Maybe Color, borderColor : Maybe Color, shadow : Maybe Shadow }
2278+focusDefaultStyle =
2279+ { backgroundColor = Nothing
2280+ , borderColor = Nothing
2281+ , shadow =
2282+ Just
2283+ { color =
2284+ Rgba (155 / 255) (203 / 255) 1 1
2285+ , offset = ( 0, 0 )
2286+ , blur = 0
2287+ , size = 3
2288+ }
2289+ }
2290+
2291+
2292+optionsToRecord : List Option -> OptionRecord
2293+optionsToRecord options =
2294+ let
2295+ combine opt record =
2296+ case opt of
2297+ HoverOption hoverable ->
2298+ case record.hover of
2299+ Nothing ->
2300+ { record | hover = Just hoverable }
2301+
2302+ _ ->
2303+ record
2304+
2305+ FocusStyleOption focusStyle ->
2306+ case record.focus of
2307+ Nothing ->
2308+ { record | focus = Just focusStyle }
2309+
2310+ _ ->
2311+ record
2312+
2313+ RenderModeOption renderMode ->
2314+ case record.mode of
2315+ Nothing ->
2316+ { record | mode = Just renderMode }
2317+
2318+ _ ->
2319+ record
2320+
2321+ andFinally record =
2322+ { hover =
2323+ case record.hover of
2324+ Nothing ->
2325+ AllowHover
2326+
2327+ Just hoverable ->
2328+ hoverable
2329+ , focus =
2330+ case record.focus of
2331+ Nothing ->
2332+ focusDefaultStyle
2333+
2334+ Just focusable ->
2335+ focusable
2336+ , mode =
2337+ case record.mode of
2338+ Nothing ->
2339+ Layout
2340+
2341+ Just actualMode ->
2342+ actualMode
2343+ }
2344+ in
2345+ andFinally <|
2346+ List.foldr combine
2347+ { hover = Nothing
2348+ , focus = Nothing
2349+ , mode = Nothing
2350+ }
2351+ options
2352+
2353+
2354+toStyleSheet : OptionRecord -> List Style -> VirtualDom.Node msg
2355+toStyleSheet options styleSheet =
2356+ case options.mode of
2357+ Layout ->
2358+ -- wrap the style node in a div to prevent `Dark Reader` from blowin up the dom.
2359+ VirtualDom.node "div"
2360+ []
2361+ [ VirtualDom.node "style"
2362+ []
2363+ [ VirtualDom.text (toStyleSheetString options styleSheet) ]
2364+ ]
2365+
2366+ NoStaticStyleSheet ->
2367+ -- wrap the style node in a div to prevent `Dark Reader` from blowin up the dom.
2368+ VirtualDom.node "div"
2369+ []
2370+ [ VirtualDom.node "style"
2371+ []
2372+ [ VirtualDom.text (toStyleSheetString options styleSheet) ]
2373+ ]
2374+
2375+ WithVirtualCss ->
2376+ VirtualDom.node "elm-ui-rules"
2377+ [ VirtualDom.property "rules"
2378+ (encodeStyles options styleSheet)
2379+ ]
2380+ []
2381+
2382+
2383+renderTopLevelValues rules =
2384+ let
2385+ withImport font =
2386+ case font of
2387+ ImportFont _ url ->
2388+ Just ("@import url('" ++ url ++ "');")
2389+
2390+ -- FontWith with ->
2391+ -- case with.url of
2392+ -- Just x ->
2393+ -- Just ("@import url('" ++ x ++ "');")
2394+ -- Nothing ->
2395+ -- Nothing
2396+ _ ->
2397+ Nothing
2398+
2399+ allNames =
2400+ List.map Tuple.first rules
2401+
2402+ fontImports ( name, typefaces ) =
2403+ let
2404+ imports =
2405+ String.join "\n" (List.filterMap withImport typefaces)
2406+ in
2407+ imports
2408+
2409+ fontAdjustments ( name, typefaces ) =
2410+ case typefaceAdjustment typefaces of
2411+ Nothing ->
2412+ String.join ""
2413+ (List.map (renderNullAdjustmentRule name) allNames)
2414+
2415+ Just adjustment ->
2416+ String.join ""
2417+ (List.map (renderFontAdjustmentRule name adjustment) allNames)
2418+ in
2419+ String.join "\n" (List.map fontImports rules)
2420+ ++ String.join "\n" (List.map fontAdjustments rules)
2421+
2422+
2423+renderNullAdjustmentRule fontToAdjust otherFontName =
2424+ let
2425+ name =
2426+ if fontToAdjust == otherFontName then
2427+ fontToAdjust
2428+
2429+ else
2430+ otherFontName ++ " ." ++ fontToAdjust
2431+ in
2432+ String.join " "
2433+ [ bracket
2434+ ("."
2435+ ++ name
2436+ ++ "."
2437+ ++ classes.sizeByCapital
2438+ ++ ", "
2439+ ++ "."
2440+ ++ name
2441+ ++ " ."
2442+ ++ classes.sizeByCapital
2443+ )
2444+ [ ( "line-height", "1" )
2445+ ]
2446+ , bracket
2447+ ("."
2448+ ++ name
2449+ ++ "."
2450+ ++ classes.sizeByCapital
2451+ ++ "> ."
2452+ ++ Internal.Style.classes.text
2453+ ++ ", ."
2454+ ++ name
2455+ ++ " ."
2456+ ++ classes.sizeByCapital
2457+ ++ " > ."
2458+ ++ Internal.Style.classes.text
2459+ )
2460+ [ ( "vertical-align", "0" )
2461+ , ( "line-height", "1" )
2462+ ]
2463+ ]
2464+
2465+
2466+fontRule name modifier ( parentAdj, textAdjustment ) =
2467+ [ bracket
2468+ ("."
2469+ ++ name
2470+ ++ "."
2471+ ++ modifier
2472+ ++ ", "
2473+ ++ "."
2474+ ++ name
2475+ ++ " ."
2476+ ++ modifier
2477+ )
2478+ parentAdj
2479+ , bracket
2480+ ("."
2481+ ++ name
2482+ ++ "."
2483+ ++ modifier
2484+ ++ "> ."
2485+ ++ Internal.Style.classes.text
2486+ ++ ", ."
2487+ ++ name
2488+ ++ " ."
2489+ ++ modifier
2490+ ++ " > ."
2491+ ++ Internal.Style.classes.text
2492+ )
2493+ textAdjustment
2494+ ]
2495+
2496+
2497+renderFontAdjustmentRule fontToAdjust ( full, capital ) otherFontName =
2498+ let
2499+ name =
2500+ if fontToAdjust == otherFontName then
2501+ fontToAdjust
2502+
2503+ else
2504+ otherFontName ++ " ." ++ fontToAdjust
2505+ in
2506+ String.join " "
2507+ (fontRule name classes.sizeByCapital capital ++ fontRule name classes.fullSize full)
2508+
2509+
2510+bracket selector rules =
2511+ let
2512+ renderPair ( name, val ) =
2513+ name ++ ": " ++ val ++ ";"
2514+ in
2515+ selector ++ " {" ++ String.join "" (List.map renderPair rules) ++ "}"
2516+
2517+
2518+fontAdjustmentRules converted =
2519+ ( [ ( "display", "block" )
2520+ ]
2521+ , [ ( "display", "inline-block" )
2522+ , ( "line-height", String.fromFloat converted.height )
2523+ , ( "vertical-align", String.fromFloat converted.vertical ++ "em" )
2524+ , ( "font-size", String.fromFloat converted.size ++ "em" )
2525+ ]
2526+ )
2527+
2528+
2529+typefaceAdjustment typefaces =
2530+ List.foldl
2531+ (\face found ->
2532+ case found of
2533+ Nothing ->
2534+ case face of
2535+ FontWith with ->
2536+ case with.adjustment of
2537+ Nothing ->
2538+ found
2539+
2540+ Just adjustment ->
2541+ Just
2542+ ( fontAdjustmentRules
2543+ (.full (convertAdjustment adjustment))
2544+ , fontAdjustmentRules
2545+ (.capital (convertAdjustment adjustment))
2546+ )
2547+
2548+ _ ->
2549+ found
2550+
2551+ Just _ ->
2552+ found
2553+ )
2554+ Nothing
2555+ typefaces
2556+
2557+
2558+fontName font =
2559+ case font of
2560+ Serif ->
2561+ "serif"
2562+
2563+ SansSerif ->
2564+ "sans-serif"
2565+
2566+ Monospace ->
2567+ "monospace"
2568+
2569+ Typeface name ->
2570+ "\"" ++ name ++ "\""
2571+
2572+ ImportFont name url ->
2573+ "\"" ++ name ++ "\""
2574+
2575+ FontWith { name } ->
2576+ "\"" ++ name ++ "\""
2577+
2578+
2579+topLevelValue rule =
2580+ case rule of
2581+ FontFamily name typefaces ->
2582+ Just ( name, typefaces )
2583+
2584+ _ ->
2585+ Nothing
2586+
2587+
2588+renderProps force (Property key val) existing =
2589+ if force then
2590+ existing ++ "\n " ++ key ++ ": " ++ val ++ " !important;"
2591+
2592+ else
2593+ existing ++ "\n " ++ key ++ ": " ++ val ++ ";"
2594+
2595+
2596+encodeStyles options stylesheet =
2597+ stylesheet
2598+ |> List.map
2599+ (\style ->
2600+ let
2601+ styled =
2602+ renderStyleRule options style Nothing
2603+ in
2604+ ( getStyleName style, Encode.list Encode.string styled )
2605+ )
2606+ |> Encode.object
2607+
2608+
2609+toStyleSheetString : OptionRecord -> List Style -> String
2610+toStyleSheetString options stylesheet =
2611+ let
2612+ combine style rendered =
2613+ { rules = rendered.rules ++ renderStyleRule options style Nothing
2614+ , topLevel =
2615+ case topLevelValue style of
2616+ Nothing ->
2617+ rendered.topLevel
2618+
2619+ Just topLevel ->
2620+ topLevel :: rendered.topLevel
2621+ }
2622+ in
2623+ case List.foldl combine { topLevel = [], rules = [] } stylesheet of
2624+ { topLevel, rules } ->
2625+ let
2626+ ruleWeight s =
2627+ if String.contains ":hover" s then
2628+ 1
2629+
2630+ else if String.contains ":focus" s then
2631+ 2
2632+
2633+ else if String.contains ":active" s then
2634+ 3
2635+
2636+ else
2637+ 0
2638+ in
2639+ renderTopLevelValues topLevel ++ String.concat (List.sortBy ruleWeight rules)
2640+
2641+
2642+renderStyle : OptionRecord -> Maybe PseudoClass -> String -> List Property -> List String
2643+renderStyle options maybePseudo selector props =
2644+ case maybePseudo of
2645+ Nothing ->
2646+ [ selector ++ "{" ++ List.foldl (renderProps False) "" props ++ "\n}" ]
2647+
2648+ Just pseudo ->
2649+ case pseudo of
2650+ Hover ->
2651+ case options.hover of
2652+ NoHover ->
2653+ []
2654+
2655+ ForceHover ->
2656+ [ selector ++ "-hv {" ++ List.foldl (renderProps True) "" props ++ "\n}" ]
2657+
2658+ AllowHover ->
2659+ [ selector ++ "-hv:hover {" ++ List.foldl (renderProps False) "" props ++ "\n}" ]
2660+
2661+ Focus ->
2662+ let
2663+ renderedProps =
2664+ List.foldl (renderProps False) "" props
2665+ in
2666+ [ selector ++ "-fs:focus {" ++ renderedProps ++ "\n}"
2667+ , ("." ++ classes.any ++ ":focus " ++ selector ++ "-fs {")
2668+ ++ renderedProps
2669+ ++ "\n}"
2670+ , (selector ++ "-fs:focus-within {")
2671+ ++ renderedProps
2672+ ++ "\n}"
2673+ , (".ui-slide-bar:focus + " ++ Internal.Style.dot classes.any ++ " .focusable-thumb" ++ selector ++ "-fs {")
2674+ ++ renderedProps
2675+ ++ "\n}"
2676+ ]
2677+
2678+ Active ->
2679+ [ selector ++ "-act:active {" ++ List.foldl (renderProps False) "" props ++ "\n}" ]
2680+
2681+
2682+renderStyleRule : OptionRecord -> Style -> Maybe PseudoClass -> List String
2683+renderStyleRule options rule maybePseudo =
2684+ case rule of
2685+ Style selector props ->
2686+ renderStyle options maybePseudo selector props
2687+
2688+ Shadows name prop ->
2689+ renderStyle options
2690+ maybePseudo
2691+ ("." ++ name)
2692+ [ Property "box-shadow" prop
2693+ ]
2694+
2695+ Transparency name transparency ->
2696+ let
2697+ opacity =
2698+ (1 - transparency)
2699+ |> min 1
2700+ |> max 0
2701+ in
2702+ renderStyle options
2703+ maybePseudo
2704+ ("." ++ name)
2705+ [ Property "opacity" (String.fromFloat opacity)
2706+ ]
2707+
2708+ FontSize i ->
2709+ renderStyle options
2710+ maybePseudo
2711+ (".font-size-" ++ String.fromInt i)
2712+ [ Property "font-size" (String.fromInt i ++ "px")
2713+ ]
2714+
2715+ FontFamily name typefaces ->
2716+ let
2717+ features =
2718+ typefaces
2719+ |> List.filterMap renderVariants
2720+ |> String.join ", "
2721+
2722+ families =
2723+ [ Property "font-family"
2724+ (typefaces
2725+ |> List.map fontName
2726+ |> String.join ", "
2727+ )
2728+ , Property "font-feature-settings" features
2729+ , Property "font-variant"
2730+ (if List.any hasSmallCaps typefaces then
2731+ "small-caps"
2732+
2733+ else
2734+ "normal"
2735+ )
2736+ ]
2737+ in
2738+ renderStyle options
2739+ maybePseudo
2740+ ("." ++ name)
2741+ families
2742+
2743+ Single class prop val ->
2744+ renderStyle options
2745+ maybePseudo
2746+ ("." ++ class)
2747+ [ Property prop val
2748+ ]
2749+
2750+ Colored class prop color ->
2751+ renderStyle options
2752+ maybePseudo
2753+ ("." ++ class)
2754+ [ Property prop (formatColor color)
2755+ ]
2756+
2757+ SpacingStyle cls x y ->
2758+ let
2759+ class =
2760+ "." ++ cls
2761+
2762+ halfX =
2763+ String.fromFloat (toFloat x / 2) ++ "px"
2764+
2765+ halfY =
2766+ String.fromFloat (toFloat y / 2) ++ "px"
2767+
2768+ xPx =
2769+ String.fromInt x ++ "px"
2770+
2771+ yPx =
2772+ String.fromInt y ++ "px"
2773+
2774+ row =
2775+ "." ++ Internal.Style.classes.row
2776+
2777+ wrappedRow =
2778+ "." ++ Internal.Style.classes.wrapped ++ row
2779+
2780+ column =
2781+ "." ++ Internal.Style.classes.column
2782+
2783+ page =
2784+ "." ++ Internal.Style.classes.page
2785+
2786+ paragraph =
2787+ "." ++ Internal.Style.classes.paragraph
2788+
2789+ left =
2790+ "." ++ Internal.Style.classes.alignLeft
2791+
2792+ right =
2793+ "." ++ Internal.Style.classes.alignRight
2794+
2795+ any =
2796+ "." ++ Internal.Style.classes.any
2797+
2798+ single =
2799+ "." ++ Internal.Style.classes.single
2800+ in
2801+ List.concat
2802+ [ renderStyle options maybePseudo (class ++ row ++ " > " ++ any ++ " + " ++ any) [ Property "margin-left" xPx ]
2803+
2804+ -- margins don't apply to last element of normal, unwrapped rows
2805+ -- , renderStyle options maybePseudo (class ++ row ++ " > " ++ any ++ ":first-child") [ Property "margin" "0" ]
2806+ -- For wrapped rows, margins always apply because we handle "canceling out" the other margins manually in the element.
2807+ , renderStyle options
2808+ maybePseudo
2809+ (class ++ wrappedRow ++ " > " ++ any)
2810+ [ Property "margin" (halfY ++ " " ++ halfX)
2811+ ]
2812+
2813+ -- , renderStyle options maybePseudo
2814+ -- (class ++ wrappedRow ++ " > " ++ any ++ ":last-child")
2815+ -- [ Property "margin-right" "0"
2816+ -- ]
2817+ -- columns
2818+ , renderStyle options maybePseudo (class ++ column ++ " > " ++ any ++ " + " ++ any) [ Property "margin-top" yPx ]
2819+ , renderStyle options maybePseudo (class ++ page ++ " > " ++ any ++ " + " ++ any) [ Property "margin-top" yPx ]
2820+ , renderStyle options maybePseudo (class ++ page ++ " > " ++ left) [ Property "margin-right" xPx ]
2821+ , renderStyle options maybePseudo (class ++ page ++ " > " ++ right) [ Property "margin-left" xPx ]
2822+ , renderStyle options
2823+ maybePseudo
2824+ (class ++ paragraph)
2825+ [ Property "line-height" ("calc(1em + " ++ String.fromInt y ++ "px)")
2826+ ]
2827+ , renderStyle options
2828+ maybePseudo
2829+ ("textarea" ++ any ++ class)
2830+ [ Property "line-height" ("calc(1em + " ++ String.fromInt y ++ "px)")
2831+ , Property "height" ("calc(100% + " ++ String.fromInt y ++ "px)")
2832+ ]
2833+
2834+ -- , renderStyle options
2835+ -- maybePseudo
2836+ -- (class ++ paragraph ++ " > " ++ any)
2837+ -- [ Property "margin-right" xPx
2838+ -- , Property "margin-bottom" yPx
2839+ -- ]
2840+ , renderStyle options
2841+ maybePseudo
2842+ (class ++ paragraph ++ " > " ++ left)
2843+ [ Property "margin-right" xPx
2844+ ]
2845+ , renderStyle options
2846+ maybePseudo
2847+ (class ++ paragraph ++ " > " ++ right)
2848+ [ Property "margin-left" xPx
2849+ ]
2850+ , renderStyle options
2851+ maybePseudo
2852+ (class ++ paragraph ++ "::after")
2853+ [ Property "content" "''"
2854+ , Property "display" "block"
2855+ , Property "height" "0"
2856+ , Property "width" "0"
2857+ , Property "margin-top" (String.fromInt (-1 * (y // 2)) ++ "px")
2858+ ]
2859+ , renderStyle options
2860+ maybePseudo
2861+ (class ++ paragraph ++ "::before")
2862+ [ Property "content" "''"
2863+ , Property "display" "block"
2864+ , Property "height" "0"
2865+ , Property "width" "0"
2866+ , Property "margin-bottom" (String.fromInt (-1 * (y // 2)) ++ "px")
2867+ ]
2868+ ]
2869+
2870+ PaddingStyle cls top right bottom left ->
2871+ let
2872+ class =
2873+ "."
2874+ ++ cls
2875+ in
2876+ renderStyle options
2877+ maybePseudo
2878+ class
2879+ [ Property "padding"
2880+ (String.fromFloat top
2881+ ++ "px "
2882+ ++ String.fromFloat right
2883+ ++ "px "
2884+ ++ String.fromFloat bottom
2885+ ++ "px "
2886+ ++ String.fromFloat left
2887+ ++ "px"
2888+ )
2889+ ]
2890+
2891+ BorderWidth cls top right bottom left ->
2892+ let
2893+ class =
2894+ "."
2895+ ++ cls
2896+ in
2897+ renderStyle options
2898+ maybePseudo
2899+ class
2900+ [ Property "border-width"
2901+ (String.fromInt top
2902+ ++ "px "
2903+ ++ String.fromInt right
2904+ ++ "px "
2905+ ++ String.fromInt bottom
2906+ ++ "px "
2907+ ++ String.fromInt left
2908+ ++ "px"
2909+ )
2910+ ]
2911+
2912+ GridTemplateStyle template ->
2913+ let
2914+ class =
2915+ ".grid-rows-"
2916+ ++ String.join "-" (List.map lengthClassName template.rows)
2917+ ++ "-cols-"
2918+ ++ String.join "-" (List.map lengthClassName template.columns)
2919+ ++ "-space-x-"
2920+ ++ lengthClassName (Tuple.first template.spacing)
2921+ ++ "-space-y-"
2922+ ++ lengthClassName (Tuple.second template.spacing)
2923+
2924+ ySpacing =
2925+ toGridLength (Tuple.second template.spacing)
2926+
2927+ xSpacing =
2928+ toGridLength (Tuple.first template.spacing)
2929+
2930+ toGridLength x =
2931+ toGridLengthHelper Nothing Nothing x
2932+
2933+ toGridLengthHelper minimum maximum x =
2934+ case x of
2935+ Px px ->
2936+ String.fromInt px ++ "px"
2937+
2938+ Content ->
2939+ case ( minimum, maximum ) of
2940+ ( Nothing, Nothing ) ->
2941+ "max-content"
2942+
2943+ ( Just minSize, Nothing ) ->
2944+ "minmax(" ++ String.fromInt minSize ++ "px, " ++ "max-content)"
2945+
2946+ ( Nothing, Just maxSize ) ->
2947+ "minmax(max-content, " ++ String.fromInt maxSize ++ "px)"
2948+
2949+ ( Just minSize, Just maxSize ) ->
2950+ "minmax(" ++ String.fromInt minSize ++ "px, " ++ String.fromInt maxSize ++ "px)"
2951+
2952+ Fill i ->
2953+ case ( minimum, maximum ) of
2954+ ( Nothing, Nothing ) ->
2955+ String.fromInt i ++ "fr"
2956+
2957+ ( Just minSize, Nothing ) ->
2958+ "minmax(" ++ String.fromInt minSize ++ "px, " ++ String.fromInt i ++ "fr" ++ "fr)"
2959+
2960+ ( Nothing, Just maxSize ) ->
2961+ "minmax(max-content, " ++ String.fromInt maxSize ++ "px)"
2962+
2963+ ( Just minSize, Just maxSize ) ->
2964+ "minmax(" ++ String.fromInt minSize ++ "px, " ++ String.fromInt maxSize ++ "px)"
2965+
2966+ Min m len ->
2967+ toGridLengthHelper (Just m) maximum len
2968+
2969+ Max m len ->
2970+ toGridLengthHelper minimum (Just m) len
2971+
2972+ msColumns =
2973+ template.columns
2974+ |> List.map toGridLength
2975+ |> String.join ySpacing
2976+ |> (\x -> "-ms-grid-columns: " ++ x ++ ";")
2977+
2978+ msRows =
2979+ template.columns
2980+ |> List.map toGridLength
2981+ |> String.join ySpacing
2982+ |> (\x -> "-ms-grid-rows: " ++ x ++ ";")
2983+
2984+ base =
2985+ class ++ "{" ++ msColumns ++ msRows ++ "}"
2986+
2987+ columns =
2988+ template.columns
2989+ |> List.map toGridLength
2990+ |> String.join " "
2991+ |> (\x -> "grid-template-columns: " ++ x ++ ";")
2992+
2993+ rows =
2994+ template.rows
2995+ |> List.map toGridLength
2996+ |> String.join " "
2997+ |> (\x -> "grid-template-rows: " ++ x ++ ";")
2998+
2999+ gapX =
3000+ "grid-column-gap:" ++ toGridLength (Tuple.first template.spacing) ++ ";"
3001+
3002+ gapY =
3003+ "grid-row-gap:" ++ toGridLength (Tuple.second template.spacing) ++ ";"
3004+
3005+ modernGrid =
3006+ class ++ "{" ++ columns ++ rows ++ gapX ++ gapY ++ "}"
3007+
3008+ supports =
3009+ "@supports (display:grid) {" ++ modernGrid ++ "}"
3010+ in
3011+ [ base
3012+ , supports
3013+ ]
3014+
3015+ GridPosition position ->
3016+ let
3017+ class =
3018+ ".grid-pos-"
3019+ ++ String.fromInt position.row
3020+ ++ "-"
3021+ ++ String.fromInt position.col
3022+ ++ "-"
3023+ ++ String.fromInt position.width
3024+ ++ "-"
3025+ ++ String.fromInt position.height
3026+
3027+ msPosition =
3028+ String.join " "
3029+ [ "-ms-grid-row: "
3030+ ++ String.fromInt position.row
3031+ ++ ";"
3032+ , "-ms-grid-row-span: "
3033+ ++ String.fromInt position.height
3034+ ++ ";"
3035+ , "-ms-grid-column: "
3036+ ++ String.fromInt position.col
3037+ ++ ";"
3038+ , "-ms-grid-column-span: "
3039+ ++ String.fromInt position.width
3040+ ++ ";"
3041+ ]
3042+
3043+ base =
3044+ class ++ "{" ++ msPosition ++ "}"
3045+
3046+ modernPosition =
3047+ String.join " "
3048+ [ "grid-row: "
3049+ ++ String.fromInt position.row
3050+ ++ " / "
3051+ ++ String.fromInt (position.row + position.height)
3052+ ++ ";"
3053+ , "grid-column: "
3054+ ++ String.fromInt position.col
3055+ ++ " / "
3056+ ++ String.fromInt (position.col + position.width)
3057+ ++ ";"
3058+ ]
3059+
3060+ modernGrid =
3061+ class ++ "{" ++ modernPosition ++ "}"
3062+
3063+ supports =
3064+ "@supports (display:grid) {" ++ modernGrid ++ "}"
3065+ in
3066+ [ base
3067+ , supports
3068+ ]
3069+
3070+ PseudoSelector class styles ->
3071+ let
3072+ renderPseudoRule style =
3073+ renderStyleRule options style (Just class)
3074+ in
3075+ List.concatMap renderPseudoRule styles
3076+
3077+ Transform transform ->
3078+ let
3079+ val =
3080+ transformValue transform
3081+
3082+ class =
3083+ transformClass transform
3084+ in
3085+ case ( class, val ) of
3086+ ( Just cls, Just v ) ->
3087+ renderStyle options
3088+ maybePseudo
3089+ ("." ++ cls)
3090+ [ Property "transform"
3091+ v
3092+ ]
3093+
3094+ _ ->
3095+ []
3096+
3097+
3098+lengthClassName : Length -> String
3099+lengthClassName x =
3100+ case x of
3101+ Px px ->
3102+ String.fromInt px ++ "px"
3103+
3104+ Content ->
3105+ "auto"
3106+
3107+ Fill i ->
3108+ String.fromInt i ++ "fr"
3109+
3110+ Min min len ->
3111+ "min" ++ String.fromInt min ++ lengthClassName len
3112+
3113+ Max max len ->
3114+ "max" ++ String.fromInt max ++ lengthClassName len
3115+
3116+
3117+formatDropShadow shadow =
3118+ String.join " "
3119+ [ String.fromFloat (Tuple.first shadow.offset) ++ "px"
3120+ , String.fromFloat (Tuple.second shadow.offset) ++ "px"
3121+ , String.fromFloat shadow.blur ++ "px"
3122+ , formatColor shadow.color
3123+ ]
3124+
3125+
3126+formatTextShadow shadow =
3127+ String.join " "
3128+ [ String.fromFloat (Tuple.first shadow.offset) ++ "px"
3129+ , String.fromFloat (Tuple.second shadow.offset) ++ "px"
3130+ , String.fromFloat shadow.blur ++ "px"
3131+ , formatColor shadow.color
3132+ ]
3133+
3134+
3135+textShadowClass shadow =
3136+ String.concat
3137+ [ "txt"
3138+ , floatClass (Tuple.first shadow.offset) ++ "px"
3139+ , floatClass (Tuple.second shadow.offset) ++ "px"
3140+ , floatClass shadow.blur ++ "px"
3141+ , formatColorClass shadow.color
3142+ ]
3143+
3144+
3145+formatBoxShadow shadow =
3146+ String.join " " <|
3147+ List.filterMap identity
3148+ [ if shadow.inset then
3149+ Just "inset"
3150+
3151+ else
3152+ Nothing
3153+ , Just <| String.fromFloat (Tuple.first shadow.offset) ++ "px"
3154+ , Just <| String.fromFloat (Tuple.second shadow.offset) ++ "px"
3155+ , Just <| String.fromFloat shadow.blur ++ "px"
3156+ , Just <| String.fromFloat shadow.size ++ "px"
3157+ , Just <| formatColor shadow.color
3158+ ]
3159+
3160+
3161+boxShadowClass shadow =
3162+ String.concat <|
3163+ [ if shadow.inset then
3164+ "box-inset"
3165+
3166+ else
3167+ "box-"
3168+ , floatClass (Tuple.first shadow.offset) ++ "px"
3169+ , floatClass (Tuple.second shadow.offset) ++ "px"
3170+ , floatClass shadow.blur ++ "px"
3171+ , floatClass shadow.size ++ "px"
3172+ , formatColorClass shadow.color
3173+ ]
3174+
3175+
3176+floatClass : Float -> String
3177+floatClass x =
3178+ String.fromInt (round (x * 255))
3179+
3180+
3181+formatColor : Color -> String
3182+formatColor (Rgba red green blue alpha) =
3183+ "rgba("
3184+ ++ String.fromInt (round (red * 255))
3185+ ++ ("," ++ String.fromInt (round (green * 255)))
3186+ ++ ("," ++ String.fromInt (round (blue * 255)))
3187+ ++ ("," ++ String.fromFloat alpha ++ ")")
3188+
3189+
3190+formatColorClass : Color -> String
3191+formatColorClass (Rgba red green blue alpha) =
3192+ floatClass red
3193+ ++ "-"
3194+ ++ floatClass green
3195+ ++ "-"
3196+ ++ floatClass blue
3197+ ++ "-"
3198+ ++ floatClass alpha
3199+
3200+
3201+spacingName x y =
3202+ "spacing-" ++ String.fromInt x ++ "-" ++ String.fromInt y
3203+
3204+
3205+paddingName top right bottom left =
3206+ "pad-"
3207+ ++ String.fromInt top
3208+ ++ "-"
3209+ ++ String.fromInt right
3210+ ++ "-"
3211+ ++ String.fromInt bottom
3212+ ++ "-"
3213+ ++ String.fromInt left
3214+
3215+
3216+paddingNameFloat top right bottom left =
3217+ "pad-"
3218+ ++ floatClass top
3219+ ++ "-"
3220+ ++ floatClass right
3221+ ++ "-"
3222+ ++ floatClass bottom
3223+ ++ "-"
3224+ ++ floatClass left
3225+
3226+
3227+getStyleName : Style -> String
3228+getStyleName style =
3229+ case style of
3230+ Shadows name _ ->
3231+ name
3232+
3233+ Transparency name o ->
3234+ name
3235+
3236+ Style class _ ->
3237+ class
3238+
3239+ FontFamily name _ ->
3240+ name
3241+
3242+ FontSize i ->
3243+ "font-size-" ++ String.fromInt i
3244+
3245+ Single class _ _ ->
3246+ class
3247+
3248+ Colored class _ _ ->
3249+ class
3250+
3251+ SpacingStyle cls x y ->
3252+ cls
3253+
3254+ PaddingStyle cls top right bottom left ->
3255+ cls
3256+
3257+ BorderWidth cls top right bottom left ->
3258+ cls
3259+
3260+ GridTemplateStyle template ->
3261+ "grid-rows-"
3262+ ++ String.join "-" (List.map lengthClassName template.rows)
3263+ ++ "-cols-"
3264+ ++ String.join "-" (List.map lengthClassName template.columns)
3265+ ++ "-space-x-"
3266+ ++ lengthClassName (Tuple.first template.spacing)
3267+ ++ "-space-y-"
3268+ ++ lengthClassName (Tuple.second template.spacing)
3269+
3270+ GridPosition pos ->
3271+ "gp grid-pos-"
3272+ ++ String.fromInt pos.row
3273+ ++ "-"
3274+ ++ String.fromInt pos.col
3275+ ++ "-"
3276+ ++ String.fromInt pos.width
3277+ ++ "-"
3278+ ++ String.fromInt pos.height
3279+
3280+ PseudoSelector selector subStyle ->
3281+ let
3282+ name =
3283+ case selector of
3284+ Focus ->
3285+ "fs"
3286+
3287+ Hover ->
3288+ "hv"
3289+
3290+ Active ->
3291+ "act"
3292+ in
3293+ List.map
3294+ (\sty ->
3295+ case getStyleName sty of
3296+ "" ->
3297+ ""
3298+
3299+ styleName ->
3300+ styleName ++ "-" ++ name
3301+ )
3302+ subStyle
3303+ |> String.join " "
3304+
3305+ Transform x ->
3306+ Maybe.withDefault "" (transformClass x)
3307+
3308+
3309+
3310+{- Constants -}
3311+
3312+
3313+asGrid : LayoutContext
3314+asGrid =
3315+ AsGrid
3316+
3317+
3318+asRow : LayoutContext
3319+asRow =
3320+ AsRow
3321+
3322+
3323+asColumn : LayoutContext
3324+asColumn =
3325+ AsColumn
3326+
3327+
3328+asEl : LayoutContext
3329+asEl =
3330+ AsEl
3331+
3332+
3333+asParagraph : LayoutContext
3334+asParagraph =
3335+ AsParagraph
3336+
3337+
3338+asTextColumn : LayoutContext
3339+asTextColumn =
3340+ AsTextColumn
3341+
3342+
3343+
3344+{- Mapping -}
3345+
3346+
3347+map : (msg -> msg1) -> Element msg -> Element msg1
3348+map fn el =
3349+ case el of
3350+ Styled styled ->
3351+ Styled
3352+ { styles = styled.styles
3353+ , html = \add context -> VirtualDom.map fn <| styled.html add context
3354+ }
3355+
3356+ Unstyled html ->
3357+ Unstyled (VirtualDom.map fn << html)
3358+
3359+ Text str ->
3360+ Text str
3361+
3362+ Empty ->
3363+ Empty
3364+
3365+
3366+mapAttr : (msg -> msg1) -> Attribute aligned msg -> Attribute aligned msg1
3367+mapAttr fn attr =
3368+ case attr of
3369+ NoAttribute ->
3370+ NoAttribute
3371+
3372+ Describe description ->
3373+ Describe description
3374+
3375+ AlignX x ->
3376+ AlignX x
3377+
3378+ AlignY y ->
3379+ AlignY y
3380+
3381+ Width x ->
3382+ Width x
3383+
3384+ Height x ->
3385+ Height x
3386+
3387+ Class x y ->
3388+ Class x y
3389+
3390+ StyleClass flag style ->
3391+ StyleClass flag style
3392+
3393+ Nearby location elem ->
3394+ Nearby location (map fn elem)
3395+
3396+ Attr htmlAttr ->
3397+ Attr (VirtualDom.mapAttribute fn htmlAttr)
3398+
3399+ TransformComponent fl trans ->
3400+ TransformComponent fl trans
3401+
3402+
3403+mapAttrFromStyle : (msg -> msg1) -> Attribute Never msg -> Attribute () msg1
3404+mapAttrFromStyle fn attr =
3405+ case attr of
3406+ NoAttribute ->
3407+ NoAttribute
3408+
3409+ Describe description ->
3410+ Describe description
3411+
3412+ AlignX x ->
3413+ AlignX x
3414+
3415+ AlignY y ->
3416+ AlignY y
3417+
3418+ Width x ->
3419+ Width x
3420+
3421+ Height x ->
3422+ Height x
3423+
3424+ -- invalidation key "border-color" as opposed to "border-color-10-10-10" that will be the key for the class
3425+ Class x y ->
3426+ Class x y
3427+
3428+ StyleClass flag style ->
3429+ StyleClass flag style
3430+
3431+ Nearby location elem ->
3432+ Nearby location (map fn elem)
3433+
3434+ Attr htmlAttr ->
3435+ Attr (VirtualDom.mapAttribute fn htmlAttr)
3436+
3437+ TransformComponent fl trans ->
3438+ TransformComponent fl trans
3439+
3440+
3441+unwrapDecorations : List (Attribute Never Never) -> List Style
3442+unwrapDecorations attrs =
3443+ case List.foldl unwrapDecsHelper ( [], Untransformed ) attrs of
3444+ ( styles, transform ) ->
3445+ Transform transform :: styles
3446+
3447+
3448+unwrapDecsHelper attr ( styles, trans ) =
3449+ case removeNever attr of
3450+ StyleClass _ style ->
3451+ ( style :: styles, trans )
3452+
3453+ TransformComponent flag component ->
3454+ ( styles, composeTransformation trans component )
3455+
3456+ _ ->
3457+ ( styles, trans )
3458+
3459+
3460+removeNever : Attribute Never Never -> Attribute () msg
3461+removeNever style =
3462+ mapAttrFromStyle Basics.never style
3463+
3464+
3465+tag : String -> Style -> Style
3466+tag label style =
3467+ case style of
3468+ Single class prop val ->
3469+ Single (label ++ "-" ++ class) prop val
3470+
3471+ Colored class prop val ->
3472+ Colored (label ++ "-" ++ class) prop val
3473+
3474+ Style class props ->
3475+ Style (label ++ "-" ++ class) props
3476+
3477+ Transparency class o ->
3478+ Transparency (label ++ "-" ++ class) o
3479+
3480+ x ->
3481+ x
3482+
3483+
3484+onlyStyles : Attribute aligned msg -> Maybe Style
3485+onlyStyles attr =
3486+ case attr of
3487+ StyleClass _ style ->
3488+ Just style
3489+
3490+ _ ->
3491+ Nothing
3492+
3493+
3494+
3495+{- Font Adjustments -}
3496+
3497+
3498+convertAdjustment adjustment =
3499+ let
3500+ lineHeight =
3501+ 1.5
3502+
3503+ base =
3504+ lineHeight
3505+
3506+ normalDescender =
3507+ (lineHeight - 1)
3508+ / 2
3509+
3510+ oldMiddle =
3511+ lineHeight / 2
3512+
3513+ newCapitalMiddle =
3514+ ((ascender - newBaseline) / 2) + newBaseline
3515+
3516+ newFullMiddle =
3517+ ((ascender - descender) / 2) + descender
3518+
3519+ lines =
3520+ [ adjustment.capital
3521+ , adjustment.baseline
3522+ , adjustment.descender
3523+ , adjustment.lowercase
3524+ ]
3525+
3526+ ascender =
3527+ Maybe.withDefault adjustment.capital (List.maximum lines)
3528+
3529+ descender =
3530+ Maybe.withDefault adjustment.descender (List.minimum lines)
3531+
3532+ newBaseline =
3533+ lines
3534+ |> List.filter (\x -> x /= descender)
3535+ |> List.minimum
3536+ |> Maybe.withDefault adjustment.baseline
3537+
3538+ capitalVertical =
3539+ 1 - ascender
3540+
3541+ capitalSize =
3542+ 1 / (ascender - newBaseline)
3543+
3544+ fullSize =
3545+ 1 / (ascender - descender)
3546+
3547+ fullVertical =
3548+ 1 - ascender
3549+
3550+ -- (oldMiddle - newFullMiddle) * 2
3551+ in
3552+ { full =
3553+ adjust fullSize (ascender - descender) fullVertical
3554+ , capital =
3555+ adjust capitalSize (ascender - newBaseline) capitalVertical
3556+ }
3557+
3558+
3559+adjust size height vertical =
3560+ { vertical = vertical
3561+ , height =
3562+ height / size
3563+ , size = size
3564+ }
deps/elm-ui/src/Internal/Style.elmnew file+1798
@@ -0,0 +1,1798 @@
1+module Internal.Style exposing (classes, dot, rules)
2+
3+{-| -}
4+
5+
6+type Class
7+ = Class String (List Rule)
8+
9+
10+type Rule
11+ = Prop String String
12+ | Child String (List Rule)
13+ | AllChildren String (List Rule)
14+ | Supports ( String, String ) (List ( String, String ))
15+ | Descriptor String (List Rule)
16+ | Adjacent String (List Rule)
17+ | Batch (List Rule)
18+
19+
20+type StyleClasses
21+ = Root
22+ | Any
23+ | Single
24+ | Row
25+ | Column
26+ | Paragraph
27+ | Page
28+ | Text
29+ | Grid
30+ | Spacer
31+
32+
33+
34+-- lengths
35+
36+
37+alignments =
38+ [ Top
39+ , Bottom
40+ , Right
41+ , Left
42+ , CenterX
43+ , CenterY
44+ ]
45+
46+
47+type Location
48+ = Above
49+ | Below
50+ | OnRight
51+ | OnLeft
52+ | Within
53+ | Behind
54+
55+
56+locations =
57+ let
58+ loc =
59+ Above
60+
61+ _ =
62+ case loc of
63+ Above ->
64+ ()
65+
66+ Below ->
67+ ()
68+
69+ OnRight ->
70+ ()
71+
72+ OnLeft ->
73+ ()
74+
75+ Within ->
76+ ()
77+
78+ Behind ->
79+ ()
80+ in
81+ [ Above
82+ , Below
83+ , OnRight
84+ , OnLeft
85+ , Within
86+ , Behind
87+ ]
88+
89+
90+selfName desc =
91+ case desc of
92+ Self Top ->
93+ dot classes.alignTop
94+
95+ Self Bottom ->
96+ dot classes.alignBottom
97+
98+ Self Right ->
99+ dot classes.alignRight
100+
101+ Self Left ->
102+ dot classes.alignLeft
103+
104+ Self CenterX ->
105+ dot classes.alignCenterX
106+
107+ Self CenterY ->
108+ dot classes.alignCenterY
109+
110+
111+contentName desc =
112+ case desc of
113+ Content Top ->
114+ dot classes.contentTop
115+
116+ Content Bottom ->
117+ dot classes.contentBottom
118+
119+ Content Right ->
120+ dot classes.contentRight
121+
122+ Content Left ->
123+ dot classes.contentLeft
124+
125+ Content CenterX ->
126+ dot classes.contentCenterX
127+
128+ Content CenterY ->
129+ dot classes.contentCenterY
130+
131+
132+classes =
133+ { root = "ui"
134+ , any = "s"
135+ , single = "e"
136+ , row = "r"
137+ , column = "c"
138+ , page = "pg"
139+ , paragraph = "p"
140+ , text = "t"
141+ , grid = "g"
142+ , imageContainer = "ic"
143+ , wrapped = "wrp"
144+
145+ -- widhts/heights
146+ , widthFill = "wf"
147+ , widthContent = "wc"
148+ , widthExact = "we"
149+ , widthFillPortion = "wfp"
150+ , heightFill = "hf"
151+ , heightContent = "hc"
152+ , heightExact = "he"
153+ , heightFillPortion = "hfp"
154+ , seButton = "sbt"
155+
156+ -- nearby elements
157+ , nearby = "nb"
158+ , above = "a"
159+ , below = "b"
160+ , onRight = "or"
161+ , onLeft = "ol"
162+ , inFront = "fr"
163+ , behind = "bh"
164+ , hasBehind = "hbh"
165+
166+ -- alignments
167+ , alignTop = "at"
168+ , alignBottom = "ab"
169+ , alignRight = "ar"
170+ , alignLeft = "al"
171+ , alignCenterX = "cx"
172+ , alignCenterY = "cy"
173+ , alignedHorizontally = "ah"
174+ , alignedVertically = "av"
175+
176+ -- space evenly
177+ , spaceEvenly = "sev"
178+ , container = "ctr"
179+ , alignContainerRight = "acr"
180+ , alignContainerBottom = "acb"
181+ , alignContainerCenterX = "accx"
182+ , alignContainerCenterY = "accy"
183+
184+ -- content alignments
185+ , contentTop = "ct"
186+ , contentBottom = "cb"
187+ , contentRight = "cr"
188+ , contentLeft = "cl"
189+ , contentCenterX = "ccx"
190+ , contentCenterY = "ccy"
191+
192+ -- selection
193+ , noTextSelection = "notxt"
194+ , cursorPointer = "cptr"
195+ , cursorText = "ctxt"
196+
197+ -- pointer events
198+ , passPointerEvents = "ppe"
199+ , capturePointerEvents = "cpe"
200+ , transparent = "clr"
201+ , opaque = "oq"
202+ , overflowHidden = "oh"
203+
204+ -- special state classes
205+ , hover = "hv"
206+
207+ -- , hoverOpaque = "hover-opaque"
208+ , focus = "fcs"
209+ , focusedWithin = "focus-within"
210+
211+ -- , focusOpaque = "focus-opaque"
212+ , active = "atv"
213+
214+ -- , activeOpaque = "active-opaque"
215+ --scrollbars
216+ , scrollbars = "sb"
217+ , scrollbarsX = "sbx"
218+ , scrollbarsY = "sby"
219+ , clip = "cp"
220+ , clipX = "cpx"
221+ , clipY = "cpy"
222+
223+ -- borders
224+ , borderNone = "bn"
225+ , borderDashed = "bd"
226+ , borderDotted = "bdt"
227+ , borderSolid = "bs"
228+
229+ -- text weight
230+ , sizeByCapital = "cap"
231+ , fullSize = "fs"
232+ , textThin = "w1"
233+ , textExtraLight = "w2"
234+ , textLight = "w3"
235+ , textNormalWeight = "w4"
236+ , textMedium = "w5"
237+ , textSemiBold = "w6"
238+ , bold = "w7"
239+ , textExtraBold = "w8"
240+ , textHeavy = "w9"
241+ , italic = "i"
242+ , strike = "sk"
243+ , underline = "u"
244+ , textUnitalicized = "tun"
245+
246+ -- text alignment
247+ , textJustify = "tj"
248+ , textJustifyAll = "tja"
249+ , textCenter = "tc"
250+ , textRight = "tr"
251+ , textLeft = "tl"
252+ , transition = "ts"
253+
254+ -- inputText
255+ , inputText = "it"
256+ , inputMultiline = "iml"
257+ , inputMultilineParent = "imlp"
258+ , inputMultilineFiller = "imlf"
259+ , inputMultilineWrapper = "implw"
260+ , inputLabel = "lbl"
261+
262+ -- link
263+ , link = "lnk"
264+ }
265+
266+
267+{-| The indulgent unicode character version.
268+-}
269+unicode =
270+ { root = "style-elements"
271+ , any = "s"
272+ , single = "e"
273+ , row = "⋯"
274+ , column = "⋮"
275+ , page = "🗏"
276+ , paragraph = "p"
277+ , text = "text"
278+ , grid = "▦"
279+
280+ -- widhts/heights
281+ , widthFill = "↔"
282+ , widthContent = "width-content"
283+ , widthExact = "width-exact"
284+ , heightFill = "↕"
285+ , heightContent = "height-content"
286+ , heightExact = "height-exact"
287+
288+ -- nearby elements
289+ , above = "above"
290+ , below = "below"
291+ , onRight = "on-right"
292+ , onLeft = "on-left"
293+ , inFront = "infront"
294+ , behind = "behind"
295+
296+ -- alignments
297+ , alignTop = "⤒"
298+ , alignBottom = "⤓"
299+ , alignRight = "⇥"
300+ , alignLeft = "⇤"
301+ , alignCenterX = "self-center-x"
302+ , alignCenterY = "self-center-y"
303+
304+ -- space evenly
305+ , spaceEvenly = "space-evenly"
306+ , container = "container"
307+
308+ -- content alignments
309+ , contentTop = "content-top"
310+ , contentBottom = "content-bottom"
311+ , contentRight = "content-right"
312+ , contentLeft = "content-left"
313+ , contentCenterX = "content-center-x"
314+ , contentCenterY = "content-center-y"
315+
316+ -- selection
317+ , noTextSelection = "no-text-selection"
318+ , cursorPointer = "cursor-pointer"
319+ , cursorText = "cursor-text"
320+
321+ -- pointer events
322+ , passPointerEvents = "pass-pointer-events"
323+ , capturePointerEvents = "capture-pointer-events"
324+ , transparent = "transparent"
325+ , opaque = "opaque"
326+
327+ --scrollbars
328+ , scrollbars = "scrollbars"
329+ , scrollbarsX = "scrollbars-x"
330+ , scrollbarsY = "scrollbars-y"
331+ , clip = "✂"
332+ , clipX = "✂x"
333+ , clipY = "✂y"
334+
335+ -- borders
336+ , borderNone = "border-none"
337+ , borderDashed = "border-dashed"
338+ , borderDotted = "border-dotted"
339+ , borderSolid = "border-solid"
340+
341+ -- text weight
342+ , textThin = "text-thin"
343+ , textExtraLight = "text-extra-light"
344+ , textLight = "text-light"
345+ , textNormalWeight = "text-normal-weight"
346+ , textMedium = "text-medium"
347+ , textSemiBold = "text-semi-bold"
348+ , bold = "bold"
349+ , textExtraBold = "text-extra-bold"
350+ , textHeavy = "text-heavy"
351+ , italic = "italic"
352+ , strike = "strike"
353+ , underline = "underline"
354+ , textUnitalicized = "text-unitalicized"
355+
356+ -- text alignment
357+ , textJustify = "text-justify"
358+ , textJustifyAll = "text-justify-all"
359+ , textCenter = "text-center"
360+ , textRight = "text-right"
361+ , textLeft = "text-left"
362+ }
363+
364+
365+single =
366+ { root = "z"
367+ , any = "s"
368+ , single = "e"
369+ , row = "r"
370+ , column = "c"
371+ , page = "l"
372+ , paragraph = "p"
373+ , text = "t"
374+ , grid = "g"
375+
376+ -- widhts/heights
377+ , widthFill = "↔"
378+ , widthContent = "wc"
379+ , widthExact = "w"
380+ , heightFill = "↕"
381+ , heightContent = "hc"
382+ , heightExact = "h"
383+
384+ -- nearby elements
385+ , above = "o"
386+ , below = "u"
387+ , onRight = "r"
388+ , onLeft = "l"
389+ , inFront = "f"
390+ , behind = "b"
391+
392+ -- alignments
393+ , alignTop = "⤒"
394+ , alignBottom = "⤓"
395+ , alignRight = "⇥"
396+ , alignLeft = "⇤"
397+ , alignCenterX = "self-center-x"
398+ , alignCenterY = "self-center-y"
399+
400+ -- space evenly
401+ , spaceEvenly = "space-evenly"
402+ , container = "container"
403+
404+ -- content alignments
405+ , contentTop = "c⤒"
406+ , contentBottom = "c⤓"
407+ , contentRight = "c⇥"
408+ , contentLeft = "c⇤"
409+ , contentCenterX = "content-center-x"
410+ , contentCenterY = "content-center-y"
411+
412+ -- selection
413+ , noTextSelection = "no-text-selection"
414+ , cursorPointer = "cursor-pointer"
415+ , cursorText = "cursor-text"
416+
417+ -- pointer events
418+ , passPointerEvents = "pass-pointer-events"
419+ , capturePointerEvents = "capture-pointer-events"
420+ , transparent = "transparent"
421+ , opaque = "opaque"
422+
423+ --scrollbars
424+ , scrollbars = "scrollbars"
425+ , scrollbarsX = "scrollbars-x"
426+ , scrollbarsY = "scrollbars-y"
427+ , clip = "✂"
428+ , clipX = "✂x"
429+ , clipY = "✂y"
430+
431+ -- borders
432+ , borderNone = "border-none"
433+ , borderDashed = "border-dashed"
434+ , borderDotted = "border-dotted"
435+ , borderSolid = "border-solid"
436+
437+ -- text weight
438+ , textThin = "text-thin"
439+ , textExtraLight = "text-extra-light"
440+ , textLight = "text-light"
441+ , textNormalWeight = "text-normal-weight"
442+ , textMedium = "text-medium"
443+ , textSemiBold = "text-semi-bold"
444+ , bold = "b"
445+ , textExtraBold = "text-extra-bold"
446+ , textHeavy = "text-heavy"
447+ , italic = "i"
448+ , strike = "-"
449+ , underline = "u"
450+ , textUnitalicized = "text-unitalicized"
451+
452+ -- text alignment
453+ , textJustify = "text-justify"
454+ , textJustifyAll = "text-justify-all"
455+ , textCenter = "text-center"
456+ , textRight = "text-right"
457+ , textLeft = "text-left"
458+ }
459+
460+
461+describeAlignment values =
462+ let
463+ createDescription alignment =
464+ let
465+ ( content, indiv ) =
466+ values alignment
467+ in
468+ [ Descriptor (contentName (Content alignment)) <|
469+ content
470+ , Child (dot classes.any)
471+ [ Descriptor (selfName <| Self alignment) indiv
472+ ]
473+ ]
474+ in
475+ Batch <|
476+ List.concatMap createDescription alignments
477+
478+
479+gridAlignments values =
480+ let
481+ createDescription alignment =
482+ [ Child (dot classes.any)
483+ [ Descriptor (selfName <| Self alignment) (values alignment)
484+ ]
485+ ]
486+ in
487+ Batch <|
488+ List.concatMap createDescription alignments
489+
490+
491+type SelfDescriptor
492+ = Self Alignment
493+
494+
495+type ContentDescriptor
496+ = Content Alignment
497+
498+
499+type Alignment
500+ = Top
501+ | Bottom
502+ | Right
503+ | Left
504+ | CenterX
505+ | CenterY
506+
507+
508+type Intermediate
509+ = Intermediate
510+ { selector : String
511+ , props : List ( String, String )
512+ , closing : String
513+ , others : List Intermediate
514+ }
515+
516+
517+emptyIntermediate : String -> String -> Intermediate
518+emptyIntermediate selector closing =
519+ Intermediate
520+ { selector = selector
521+ , props = []
522+ , closing = closing
523+ , others = []
524+ }
525+
526+
527+renderRules : Intermediate -> List Rule -> Intermediate
528+renderRules (Intermediate parent) rulesToRender =
529+ let
530+ generateIntermediates rule rendered =
531+ case rule of
532+ Prop name val ->
533+ { rendered | props = ( name, val ) :: rendered.props }
534+
535+ Supports ( prop, value ) props ->
536+ { rendered
537+ | others =
538+ Intermediate
539+ { selector = "@supports (" ++ prop ++ ":" ++ value ++ ") {" ++ parent.selector
540+ , props = props
541+ , closing = "\n}"
542+ , others = []
543+ }
544+ :: rendered.others
545+ }
546+
547+ Adjacent selector adjRules ->
548+ { rendered
549+ | others =
550+ renderRules
551+ (emptyIntermediate (parent.selector ++ " + " ++ selector) "")
552+ adjRules
553+ :: rendered.others
554+ }
555+
556+ Child child childRules ->
557+ { rendered
558+ | others =
559+ renderRules
560+ (emptyIntermediate (parent.selector ++ " > " ++ child) "")
561+ childRules
562+ :: rendered.others
563+ }
564+
565+ AllChildren child childRules ->
566+ { rendered
567+ | others =
568+ renderRules
569+ (emptyIntermediate (parent.selector ++ " " ++ child) "")
570+ childRules
571+ :: rendered.others
572+ }
573+
574+ Descriptor descriptor descriptorRules ->
575+ { rendered
576+ | others =
577+ renderRules
578+ (emptyIntermediate (parent.selector ++ descriptor) "")
579+ descriptorRules
580+ :: rendered.others
581+ }
582+
583+ Batch batched ->
584+ { rendered
585+ | others =
586+ renderRules (emptyIntermediate parent.selector "") batched
587+ :: rendered.others
588+ }
589+ in
590+ Intermediate <| List.foldr generateIntermediates parent rulesToRender
591+
592+
593+render : List Class -> String
594+render classNames =
595+ let
596+ renderValues values =
597+ values
598+ |> List.map (\( x, y ) -> " " ++ x ++ ": " ++ y ++ ";")
599+ |> String.join "\n"
600+
601+ renderClass rule =
602+ case rule.props of
603+ [] ->
604+ ""
605+
606+ _ ->
607+ rule.selector ++ " {\n" ++ renderValues rule.props ++ rule.closing ++ "\n}"
608+
609+ renderIntermediate (Intermediate rule) =
610+ renderClass rule
611+ ++ String.join "\n" (List.map renderIntermediate rule.others)
612+ in
613+ classNames
614+ |> List.foldr
615+ (\(Class name styleRules) existing ->
616+ renderRules (emptyIntermediate name "") styleRules :: existing
617+ )
618+ []
619+ |> List.map renderIntermediate
620+ |> String.join "\n"
621+
622+
623+renderCompact : List Class -> String
624+renderCompact styleClasses =
625+ let
626+ renderValues values =
627+ values
628+ |> List.map (\( x, y ) -> x ++ ":" ++ y ++ ";")
629+ |> String.concat
630+
631+ renderClass rule =
632+ case rule.props of
633+ [] ->
634+ ""
635+
636+ _ ->
637+ rule.selector ++ "{" ++ renderValues rule.props ++ rule.closing ++ "}"
638+
639+ renderIntermediate (Intermediate rule) =
640+ renderClass rule
641+ ++ String.concat (List.map renderIntermediate rule.others)
642+ in
643+ styleClasses
644+ |> List.foldr
645+ (\(Class name styleRules) existing ->
646+ renderRules (emptyIntermediate name "") styleRules :: existing
647+ )
648+ []
649+ |> List.map renderIntermediate
650+ |> String.concat
651+
652+
653+viewportRules : String
654+viewportRules =
655+ """html, body {
656+ height: 100%;
657+ width: 100%;
658+} """ ++ rules
659+
660+
661+describeText : String -> List Rule -> Rule
662+describeText cls props =
663+ Descriptor cls
664+ (List.map makeImportant props
665+ ++ [ Child ".text"
666+ props
667+ , Child ".el"
668+ props
669+ , Child ".el > .text"
670+ props
671+ ]
672+ )
673+
674+
675+makeImportant : Rule -> Rule
676+makeImportant rule =
677+ case rule of
678+ Prop name prop ->
679+ Prop name (prop ++ " !important")
680+
681+ _ ->
682+ rule
683+
684+
685+dot c =
686+ "." ++ c
687+
688+
689+overrides =
690+ """@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {"""
691+ ++ dot classes.any
692+ ++ dot classes.row
693+ ++ " > "
694+ ++ dot classes.any
695+ ++ " { flex-basis: auto !important; } "
696+ ++ dot classes.any
697+ ++ dot classes.row
698+ ++ " > "
699+ ++ dot classes.any
700+ ++ dot classes.container
701+ ++ " { flex-basis: auto !important; }}"
702+ ++ inputTextReset
703+ ++ sliderReset
704+ ++ trackReset
705+ ++ thumbReset
706+ ++ explainer
707+
708+
709+inputTextReset =
710+ """
711+input[type="search"],
712+input[type="search"]::-webkit-search-decoration,
713+input[type="search"]::-webkit-search-cancel-button,
714+input[type="search"]::-webkit-search-results-button,
715+input[type="search"]::-webkit-search-results-decoration {
716+ -webkit-appearance:none;
717+}
718+"""
719+
720+
721+sliderReset =
722+ """
723+input[type=range] {
724+ -webkit-appearance: none;
725+ background: transparent;
726+ position:absolute;
727+ left:0;
728+ top:0;
729+ z-index:10;
730+ width: 100%;
731+ outline: dashed 1px;
732+ height: 100%;
733+ opacity: 0;
734+}
735+"""
736+
737+
738+trackReset =
739+ """
740+input[type=range]::-moz-range-track {
741+ background: transparent;
742+ cursor: pointer;
743+}
744+input[type=range]::-ms-track {
745+ background: transparent;
746+ cursor: pointer;
747+}
748+input[type=range]::-webkit-slider-runnable-track {
749+ background: transparent;
750+ cursor: pointer;
751+}
752+"""
753+
754+
755+thumbReset =
756+ """
757+input[type=range]::-webkit-slider-thumb {
758+ -webkit-appearance: none;
759+ opacity: 0.5;
760+ width: 80px;
761+ height: 80px;
762+ background-color: black;
763+ border:none;
764+ border-radius: 5px;
765+}
766+input[type=range]::-moz-range-thumb {
767+ opacity: 0.5;
768+ width: 80px;
769+ height: 80px;
770+ background-color: black;
771+ border:none;
772+ border-radius: 5px;
773+}
774+input[type=range]::-ms-thumb {
775+ opacity: 0.5;
776+ width: 80px;
777+ height: 80px;
778+ background-color: black;
779+ border:none;
780+ border-radius: 5px;
781+}
782+input[type=range][orient=vertical]{
783+ writing-mode: bt-lr; /* IE */
784+ -webkit-appearance: slider-vertical; /* WebKit */
785+}
786+"""
787+
788+
789+explainer =
790+ """
791+.explain {
792+ border: 6px solid rgb(174, 121, 15) !important;
793+}
794+.explain > .""" ++ classes.any ++ """ {
795+ border: 4px dashed rgb(0, 151, 167) !important;
796+}
797+
798+.ctr {
799+ border: none !important;
800+}
801+.explain > .ctr > .""" ++ classes.any ++ """ {
802+ border: 4px dashed rgb(0, 151, 167) !important;
803+}
804+
805+"""
806+
807+
808+commonValues =
809+ List.concat
810+ [ List.map
811+ (\x ->
812+ Class (".border-" ++ String.fromInt x) [ Prop "border-width" (String.fromInt x ++ "px") ]
813+ )
814+ (List.range 0 6)
815+ , List.map
816+ (\i ->
817+ Class (".font-size-" ++ String.fromInt i) [ Prop "font-size" (String.fromInt i ++ "px") ]
818+ )
819+ (List.range 8 32)
820+ , List.map
821+ (\i ->
822+ Class (".p-" ++ String.fromInt i) [ Prop "padding" (String.fromInt i ++ "px") ]
823+ )
824+ (List.range 0 24)
825+
826+ -- Common Font Variants
827+ , [ Class ".v-smcp"
828+ [ Prop "font-variant" "small-caps"
829+ ]
830+ , Class ".v-smcp-off"
831+ [ Prop "font-variant" "normal"
832+ ]
833+ ]
834+
835+ -- , fontVariant "smcp"
836+ , fontVariant "zero"
837+ , fontVariant "onum"
838+ , fontVariant "liga"
839+ , fontVariant "dlig"
840+ , fontVariant "ordn"
841+ , fontVariant "tnum"
842+ , fontVariant "afrc"
843+ , fontVariant "frac"
844+ ]
845+
846+
847+fontVariant var =
848+ [ Class (".v-" ++ var)
849+ [ Prop "font-feature-settings" ("\"" ++ var ++ "\"")
850+ ]
851+ , Class (".v-" ++ var ++ "-off")
852+ [ Prop "font-feature-settings" ("\"" ++ var ++ "\" 0")
853+ ]
854+ ]
855+
856+
857+rules : String
858+rules =
859+ overrides
860+ ++ renderCompact (baseSheet ++ commonValues)
861+
862+
863+elDescription =
864+ [ Prop "display" "flex"
865+ , Prop "flex-direction" "column"
866+ , Prop "white-space" "pre"
867+ , Descriptor (dot classes.hasBehind)
868+ [ Prop "z-index" "0"
869+ , Child (dot classes.behind)
870+ [ Prop "z-index" "-1"
871+ ]
872+ ]
873+ , Descriptor (dot classes.seButton)
874+ -- Special default for text in a button.
875+ -- This is overridden is they put the text inside an `el`
876+ [ Child (dot classes.text)
877+ [ Descriptor (dot classes.heightFill)
878+ [ Prop "flex-grow" "0"
879+ ]
880+ , Descriptor (dot classes.widthFill)
881+ [ Prop "align-self" "auto !important"
882+ ]
883+ ]
884+ ]
885+ , Child (dot classes.heightContent)
886+ [ Prop "height" "auto"
887+ ]
888+ , Child (dot classes.heightFill)
889+ [ Prop "flex-grow" "100000"
890+ ]
891+ , Child (dot classes.widthFill)
892+ [ -- alignLeft, alignRight, centerX are overridden by width.
893+ -- Prop "align-self" "stretch !important"
894+ Prop "width" "100%"
895+ ]
896+ , Child (dot classes.widthFillPortion)
897+ [ Prop "width" "100%"
898+ ]
899+ , Child (dot classes.widthContent)
900+ [ Prop "align-self" "flex-start"
901+ ]
902+
903+ -- , Child (dot classes.widthFill)
904+ -- [ Prop "align-self" "stretch"
905+ -- , Descriptor (dot classes.alignedHorizontally)
906+ -- [ Prop "width" "100%"
907+ -- ]
908+ -- ]
909+ , describeAlignment <|
910+ \alignment ->
911+ case alignment of
912+ Top ->
913+ ( [ Prop "justify-content" "flex-start" ]
914+ , [ Prop "margin-bottom" "auto !important"
915+ , Prop "margin-top" "0 !important"
916+ ]
917+ )
918+
919+ Bottom ->
920+ ( [ Prop "justify-content" "flex-end" ]
921+ , [ Prop "margin-top" "auto !important"
922+ , Prop "margin-bottom" "0 !important"
923+ ]
924+ )
925+
926+ Right ->
927+ ( [ Prop "align-items" "flex-end" ]
928+ , [ Prop "align-self" "flex-end" ]
929+ )
930+
931+ Left ->
932+ ( [ Prop "align-items" "flex-start" ]
933+ , [ Prop "align-self" "flex-start" ]
934+ )
935+
936+ CenterX ->
937+ ( [ Prop "align-items" "center" ]
938+ , [ Prop "align-self" "center"
939+ ]
940+ )
941+
942+ CenterY ->
943+ ( [ -- Prop "justify-content" "center"
944+ Child (dot classes.any)
945+ [ Prop "margin-top" "auto"
946+ , Prop "margin-bottom" "auto"
947+ ]
948+ ]
949+ , [ Prop "margin-top" "auto !important"
950+ , Prop "margin-bottom" "auto !important"
951+ ]
952+ )
953+ ]
954+
955+
956+baseSheet =
957+ [ Class "html,body"
958+ [ Prop "height" "100%"
959+ , Prop "padding" "0"
960+ , Prop "margin" "0"
961+ ]
962+ , Class (dot classes.any ++ dot classes.single ++ dot classes.imageContainer)
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+ ]
976+ ]
977+ , Class (dot classes.any ++ ":focus")
978+ [ Prop "outline" "none"
979+ ]
980+ , Class (dot classes.root)
981+ [ Prop "width" "100%"
982+ , Prop "height" "auto"
983+ , Prop "min-height" "100%"
984+ , Prop "z-index" "0"
985+ , Descriptor
986+ (dot classes.any
987+ -- ++ dot classes.single
988+ ++ dot classes.heightFill
989+ )
990+ [ Prop "height" "100%"
991+ , Child (dot classes.heightFill)
992+ [ Prop "height" "100%"
993+ ]
994+ ]
995+ , Child (dot classes.inFront)
996+ [ Descriptor (dot classes.nearby)
997+ [ Prop "position" "fixed"
998+ , Prop "z-index" "20"
999+ ]
1000+ ]
1001+ ]
1002+ , Class (dot classes.nearby)
1003+ [ Prop "position" "relative"
1004+ , Prop "border" "none"
1005+ , Prop "display" "flex"
1006+ , Prop "flex-direction" "row"
1007+ , Prop "flex-basis" "auto"
1008+ , Descriptor (dot classes.single)
1009+ elDescription
1010+ , Batch <|
1011+ (\fn -> List.map fn locations) <|
1012+ \loc ->
1013+ case loc of
1014+ Above ->
1015+ Descriptor (dot classes.above)
1016+ [ Prop "position" "absolute"
1017+ , Prop "bottom" "100%"
1018+ , Prop "left" "0"
1019+ , Prop "width" "100%"
1020+ , Prop "z-index" "20"
1021+ , Prop "margin" "0 !important"
1022+ , Child (dot classes.heightFill)
1023+ [ Prop "height" "auto"
1024+ ]
1025+ , Child (dot classes.widthFill)
1026+ [ Prop "width" "100%"
1027+ ]
1028+ , Prop "pointer-events" "none"
1029+ , Child "*"
1030+ [ Prop "pointer-events" "auto"
1031+ ]
1032+ ]
1033+
1034+ Below ->
1035+ Descriptor (dot classes.below)
1036+ [ Prop "position" "absolute"
1037+ , Prop "bottom" "0"
1038+ , Prop "left" "0"
1039+ , Prop "height" "0"
1040+ , Prop "width" "100%"
1041+ , Prop "z-index" "20"
1042+ , Prop "margin" "0 !important"
1043+ , Prop "pointer-events" "none"
1044+ , Child "*"
1045+ [ Prop "pointer-events" "auto"
1046+ ]
1047+ , Child (dot classes.heightFill)
1048+ [ Prop "height" "auto"
1049+ ]
1050+ ]
1051+
1052+ OnRight ->
1053+ Descriptor (dot classes.onRight)
1054+ [ Prop "position" "absolute"
1055+ , Prop "left" "100%"
1056+ , Prop "top" "0"
1057+ , Prop "height" "100%"
1058+ , Prop "margin" "0 !important"
1059+ , Prop "z-index" "20"
1060+ , Prop "pointer-events" "none"
1061+ , Child "*"
1062+ [ Prop "pointer-events" "auto"
1063+ ]
1064+ ]
1065+
1066+ OnLeft ->
1067+ Descriptor (dot classes.onLeft)
1068+ [ Prop "position" "absolute"
1069+ , Prop "right" "100%"
1070+ , Prop "top" "0"
1071+ , Prop "height" "100%"
1072+ , Prop "margin" "0 !important"
1073+ , Prop "z-index" "20"
1074+ , Prop "pointer-events" "none"
1075+ , Child "*"
1076+ [ Prop "pointer-events" "auto"
1077+ ]
1078+ ]
1079+
1080+ Within ->
1081+ Descriptor (dot classes.inFront)
1082+ [ Prop "position" "absolute"
1083+ , Prop "width" "100%"
1084+ , Prop "height" "100%"
1085+ , Prop "left" "0"
1086+ , Prop "top" "0"
1087+ , Prop "margin" "0 !important"
1088+ , Prop "pointer-events" "none"
1089+ , Child "*"
1090+ [ Prop "pointer-events" "auto"
1091+ ]
1092+ ]
1093+
1094+ Behind ->
1095+ Descriptor (dot classes.behind)
1096+ [ Prop "position" "absolute"
1097+ , Prop "width" "100%"
1098+ , Prop "height" "100%"
1099+ , Prop "left" "0"
1100+ , Prop "top" "0"
1101+ , Prop "margin" "0 !important"
1102+ , Prop "z-index" "0"
1103+ , Prop "pointer-events" "none"
1104+ , Child "*"
1105+ [ Prop "pointer-events" "auto"
1106+ ]
1107+ ]
1108+ ]
1109+ , Class (dot classes.any)
1110+ [ Prop "position" "relative"
1111+ , Prop "border" "none"
1112+ , Prop "flex-shrink" "0"
1113+ , Prop "display" "flex"
1114+ , Prop "flex-direction" "row"
1115+ , Prop "flex-basis" "auto"
1116+ , Prop "resize" "none"
1117+ , Prop "font-feature-settings" "inherit"
1118+
1119+ -- , Prop "flex-basis" "0%"
1120+ , Prop "box-sizing" "border-box"
1121+ , Prop "margin" "0"
1122+ , Prop "padding" "0"
1123+ , Prop "border-width" "0"
1124+ , Prop "border-style" "solid"
1125+
1126+ -- inheritable font properties
1127+ , Prop "font-size" "inherit"
1128+ , Prop "color" "inherit"
1129+ , Prop "font-family" "inherit"
1130+ , Prop "line-height" "1"
1131+ , Prop "font-weight" "inherit"
1132+
1133+ -- Text decoration is *mandatorily inherited* in the css spec.
1134+ -- There's no way to change this. How crazy is that?
1135+ , Prop "text-decoration" "none"
1136+ , Prop "font-style" "inherit"
1137+ , Descriptor (dot classes.wrapped)
1138+ [ Prop "flex-wrap" "wrap"
1139+ ]
1140+ , Descriptor (dot classes.noTextSelection)
1141+ [ Prop "-moz-user-select" "none"
1142+ , Prop "-webkit-user-select" "none"
1143+ , Prop "-ms-user-select" "none"
1144+ , Prop "user-select" "none"
1145+ ]
1146+ , Descriptor (dot classes.cursorPointer)
1147+ [ Prop "cursor" "pointer"
1148+ ]
1149+ , Descriptor (dot classes.cursorText)
1150+ [ Prop "cursor" "text"
1151+ ]
1152+ , Descriptor (dot classes.passPointerEvents)
1153+ [ Prop "pointer-events" "none !important"
1154+ ]
1155+ , Descriptor (dot classes.capturePointerEvents)
1156+ [ Prop "pointer-events" "auto !important"
1157+ ]
1158+ , Descriptor (dot classes.transparent)
1159+ [ Prop "opacity" "0"
1160+ ]
1161+ , Descriptor (dot classes.opaque)
1162+ [ Prop "opacity" "1"
1163+ ]
1164+ , Descriptor (dot (classes.hover ++ classes.transparent) ++ ":hover")
1165+ [ Prop "opacity" "0"
1166+ ]
1167+ , Descriptor (dot (classes.hover ++ classes.opaque) ++ ":hover")
1168+ [ Prop "opacity" "1"
1169+ ]
1170+ , Descriptor (dot (classes.focus ++ classes.transparent) ++ ":focus")
1171+ [ Prop "opacity" "0"
1172+ ]
1173+ , Descriptor (dot (classes.focus ++ classes.opaque) ++ ":focus")
1174+ [ Prop "opacity" "1"
1175+ ]
1176+ , Descriptor (dot (classes.active ++ classes.transparent) ++ ":active")
1177+ [ Prop "opacity" "0"
1178+ ]
1179+ , Descriptor (dot (classes.active ++ classes.opaque) ++ ":active")
1180+ [ Prop "opacity" "1"
1181+ ]
1182+ , Descriptor (dot classes.transition)
1183+ [ Prop "transition"
1184+ (String.join ", " <|
1185+ List.map (\x -> x ++ " 160ms")
1186+ [ "transform"
1187+ , "opacity"
1188+ , "filter"
1189+ , "background-color"
1190+ , "color"
1191+ , "font-size"
1192+ ]
1193+ )
1194+ ]
1195+ , Descriptor (dot classes.scrollbars)
1196+ [ Prop "overflow" "auto"
1197+ , Prop "flex-shrink" "1"
1198+ ]
1199+ , Descriptor (dot classes.scrollbarsX)
1200+ [ Prop "overflow-x" "auto"
1201+ , Descriptor (dot classes.row)
1202+ [ Prop "flex-shrink" "1"
1203+ ]
1204+ ]
1205+ , Descriptor (dot classes.scrollbarsY)
1206+ [ Prop "overflow-y" "auto"
1207+ , Descriptor (dot classes.column)
1208+ [ Prop "flex-shrink" "1"
1209+ ]
1210+ , Descriptor (dot classes.single)
1211+ [ Prop "flex-shrink" "1"
1212+ ]
1213+ ]
1214+ , Descriptor (dot classes.clip)
1215+ [ Prop "overflow" "hidden"
1216+ ]
1217+ , Descriptor (dot classes.clipX)
1218+ [ Prop "overflow-x" "hidden"
1219+ ]
1220+ , Descriptor (dot classes.clipY)
1221+ [ Prop "overflow-y" "hidden"
1222+ ]
1223+ , Descriptor (dot classes.widthContent)
1224+ [ Prop "width" "auto"
1225+ ]
1226+ , Descriptor (dot classes.borderNone)
1227+ [ Prop "border-width" "0"
1228+ ]
1229+ , Descriptor (dot classes.borderDashed)
1230+ [ Prop "border-style" "dashed"
1231+ ]
1232+ , Descriptor (dot classes.borderDotted)
1233+ [ Prop "border-style" "dotted"
1234+ ]
1235+ , Descriptor (dot classes.borderSolid)
1236+ [ Prop "border-style" "solid"
1237+ ]
1238+ , Descriptor (dot classes.text)
1239+ [ Prop "white-space" "pre"
1240+ , Prop "display" "inline-block"
1241+ ]
1242+ , Descriptor (dot classes.inputText)
1243+ -- chrome and safari have a minimum recognized line height for text input of 1.05
1244+ -- If it's 1, it bumps up to something like 1.2
1245+ [ Prop "line-height" "1.05"
1246+ , Prop "background" "transparent"
1247+ , Prop "text-align" "inherit"
1248+ ]
1249+ , Descriptor (dot classes.single)
1250+ elDescription
1251+ , Descriptor (dot classes.row)
1252+ [ Prop "display" "flex"
1253+ , Prop "flex-direction" "row"
1254+ , Child (dot classes.any)
1255+ [ Prop "flex-basis" "0%"
1256+ , Descriptor (dot classes.widthExact)
1257+ [ Prop "flex-basis" "auto"
1258+ ]
1259+ , Descriptor (dot classes.link)
1260+ [ Prop "flex-basis" "auto"
1261+ ]
1262+ ]
1263+ , Child (dot classes.heightFill)
1264+ [ -- alignTop, centerY, and alignBottom need to be disabled
1265+ Prop "align-self" "stretch !important"
1266+ ]
1267+ , Child (dot classes.heightFillPortion)
1268+ [ -- alignTop, centerY, and alignBottom need to be disabled
1269+ Prop "align-self" "stretch !important"
1270+ ]
1271+
1272+ -- TODO:: This may be necessary..should it move to classes.heightFIll?
1273+ -- , Child (dot classes.heightFillBetween)
1274+ -- [ Prop "align-self" "stretch"
1275+ -- , Descriptor ".aligned-vertically"
1276+ -- [ Prop "height" "100%"
1277+ -- ]
1278+ -- ]
1279+ , Child (dot classes.widthFill)
1280+ [ Prop "flex-grow" "100000"
1281+ ]
1282+ , Child (dot classes.container)
1283+ [ Prop "flex-grow" "0"
1284+ , Prop "flex-basis" "auto"
1285+ , Prop "align-self" "stretch"
1286+ ]
1287+
1288+ -- , Child "alignLeft:last-of-type.align-container-left"
1289+ -- [ Prop "flex-grow" "1"
1290+ -- ]
1291+ -- alignRight -> <u>
1292+ --centerX -> <s>
1293+ , Child ("u:first-of-type." ++ classes.alignContainerRight)
1294+ [ Prop "flex-grow" "1"
1295+ ]
1296+
1297+ -- first center y
1298+ , Child ("s:first-of-type." ++ classes.alignContainerCenterX)
1299+ [ Prop "flex-grow" "1"
1300+ , Child (dot classes.alignCenterX)
1301+ [ Prop "margin-left" "auto !important"
1302+ ]
1303+ ]
1304+ , Child ("s:last-of-type." ++ classes.alignContainerCenterX)
1305+ [ Prop "flex-grow" "1"
1306+ , Child (dot classes.alignCenterX)
1307+ [ Prop "margin-right" "auto !important"
1308+ ]
1309+ ]
1310+
1311+ -- lonley centerX
1312+ , Child ("s:only-of-type." ++ classes.alignContainerCenterX)
1313+ [ Prop "flex-grow" "1"
1314+ , Child (dot classes.alignCenterY)
1315+ [ Prop "margin-top" "auto !important"
1316+ , Prop "margin-bottom" "auto !important"
1317+ ]
1318+ ]
1319+
1320+ -- alignBottom's after a centerX should not grow
1321+ , Child
1322+ ("s:last-of-type." ++ classes.alignContainerCenterX ++ " ~ u")
1323+ [ Prop "flex-grow" "0"
1324+ ]
1325+
1326+ -- centerX's after an alignBottom should be ignored
1327+ , Child ("u:first-of-type." ++ classes.alignContainerRight ++ " ~ s." ++ classes.alignContainerCenterX)
1328+ -- Bottom alignment always overrides center alignment
1329+ [ Prop "flex-grow" "0"
1330+ ]
1331+ , describeAlignment <|
1332+ \alignment ->
1333+ case alignment of
1334+ Top ->
1335+ ( [ Prop "align-items" "flex-start" ]
1336+ , [ Prop "align-self" "flex-start"
1337+ ]
1338+ )
1339+
1340+ Bottom ->
1341+ ( [ Prop "align-items" "flex-end" ]
1342+ , [ Prop "align-self" "flex-end"
1343+ ]
1344+ )
1345+
1346+ Right ->
1347+ ( [ Prop "justify-content" "flex-end"
1348+ ]
1349+ , []
1350+ )
1351+
1352+ Left ->
1353+ ( [ Prop "justify-content" "flex-start"
1354+ ]
1355+ , []
1356+ )
1357+
1358+ CenterX ->
1359+ ( [ Prop "justify-content" "center"
1360+ ]
1361+ , []
1362+ )
1363+
1364+ CenterY ->
1365+ ( [ Prop "align-items" "center" ]
1366+ , [ Prop "align-self" "center"
1367+ ]
1368+ )
1369+
1370+ -- Must be below the alignment rules or else it interferes
1371+ , Descriptor (dot classes.spaceEvenly)
1372+ [ Prop "justify-content" "space-between"
1373+ ]
1374+ , Descriptor (dot classes.inputLabel)
1375+ [ Prop "align-items" "baseline"
1376+ ]
1377+ ]
1378+ , Descriptor (dot classes.column)
1379+ [ Prop "display" "flex"
1380+ , Prop "flex-direction" "column"
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.
1391+ [ Prop "flex-basis" "0px"
1392+ , Prop "min-height" "min-content"
1393+ , Descriptor (dot classes.heightExact)
1394+ [ Prop "flex-basis" "auto"
1395+ ]
1396+ ]
1397+ , Child (dot classes.heightFill)
1398+ [ Prop "flex-grow" "100000"
1399+ ]
1400+ , Child (dot classes.widthFill)
1401+ [ -- alignLeft, alignRight, centerX need to be disabled
1402+ -- Prop "align-self" "stretch !important"
1403+ Prop "width" "100%"
1404+ ]
1405+ , Child (dot classes.widthFillPortion)
1406+ [ -- alignLeft, alignRight, centerX need to be disabled
1407+ -- Prop "align-self" "stretch !important"
1408+ Prop "width" "100%"
1409+ ]
1410+
1411+ -- TODO:: This might be necessary, maybe it should move to widthFill?
1412+ -- , Child (dot classes.widthFill)
1413+ -- [ Prop "align-self" "stretch"
1414+ -- , Descriptor (dot classes.alignedHorizontally)
1415+ -- [ Prop "width" "100%"
1416+ -- ]
1417+ -- ]
1418+ , Child (dot classes.widthContent)
1419+ [ Prop "align-self" "flex-start"
1420+ ]
1421+
1422+ -- , Child "alignTop:last-of-type.align-container-top"
1423+ -- [ Prop "flex-grow" "1"
1424+ -- ]
1425+ , Child ("u:first-of-type." ++ classes.alignContainerBottom)
1426+ [ Prop "flex-grow" "1"
1427+ ]
1428+
1429+ -- centerY -> <s>
1430+ -- alignBottom -> <u>
1431+ -- first center y
1432+ , Child ("s:first-of-type." ++ classes.alignContainerCenterY)
1433+ [ Prop "flex-grow" "1"
1434+ , Child (dot classes.alignCenterY)
1435+ [ Prop "margin-top" "auto !important"
1436+ , Prop "margin-bottom" "0 !important"
1437+ ]
1438+ ]
1439+ , Child ("s:last-of-type." ++ classes.alignContainerCenterY)
1440+ [ Prop "flex-grow" "1"
1441+ , Child (dot classes.alignCenterY)
1442+ [ Prop "margin-bottom" "auto !important"
1443+ , Prop "margin-top" "0 !important"
1444+ ]
1445+ ]
1446+
1447+ -- lonley centerY
1448+ , Child ("s:only-of-type." ++ classes.alignContainerCenterY)
1449+ [ Prop "flex-grow" "1"
1450+ , Child (dot classes.alignCenterY)
1451+ [ Prop "margin-top" "auto !important"
1452+ , Prop "margin-bottom" "auto !important"
1453+ ]
1454+ ]
1455+
1456+ -- alignBottom's after a centerY should not grow
1457+ , Child ("s:last-of-type." ++ classes.alignContainerCenterY ++ " ~ u")
1458+ [ Prop "flex-grow" "0"
1459+ ]
1460+
1461+ -- centerY's after an alignBottom should be ignored
1462+ , Child ("u:first-of-type." ++ classes.alignContainerBottom ++ " ~ s." ++ classes.alignContainerCenterY)
1463+ -- Bottom alignment always overrides center alignment
1464+ [ Prop "flex-grow" "0"
1465+ ]
1466+ , describeAlignment <|
1467+ \alignment ->
1468+ case alignment of
1469+ Top ->
1470+ ( [ Prop "justify-content" "flex-start" ]
1471+ , [ Prop "margin-bottom" "auto" ]
1472+ )
1473+
1474+ Bottom ->
1475+ ( [ Prop "justify-content" "flex-end" ]
1476+ , [ Prop "margin-top" "auto" ]
1477+ )
1478+
1479+ Right ->
1480+ ( [ Prop "align-items" "flex-end" ]
1481+ , [ Prop "align-self" "flex-end" ]
1482+ )
1483+
1484+ Left ->
1485+ ( [ Prop "align-items" "flex-start" ]
1486+ , [ Prop "align-self" "flex-start" ]
1487+ )
1488+
1489+ CenterX ->
1490+ ( [ Prop "align-items" "center" ]
1491+ , [ Prop "align-self" "center"
1492+ ]
1493+ )
1494+
1495+ CenterY ->
1496+ ( [ Prop "justify-content" "center" ]
1497+ , []
1498+ )
1499+ , Child (dot classes.container)
1500+ [ Prop "flex-grow" "0"
1501+ , Prop "flex-basis" "auto"
1502+ , Prop "width" "100%"
1503+ , Prop "align-self" "stretch !important"
1504+ ]
1505+ , Descriptor (dot classes.spaceEvenly)
1506+ [ Prop "justify-content" "space-between"
1507+ ]
1508+ ]
1509+ , Descriptor (dot classes.grid)
1510+ [ Prop "display" "-ms-grid"
1511+ , Child ".gp"
1512+ [ Child (dot classes.any)
1513+ [ Prop "width" "100%"
1514+ ]
1515+ ]
1516+ , Supports ( "display", "grid" )
1517+ [ ( "display", "grid" )
1518+ ]
1519+ , gridAlignments <|
1520+ \alignment ->
1521+ case alignment of
1522+ Top ->
1523+ [ Prop "justify-content" "flex-start" ]
1524+
1525+ Bottom ->
1526+ [ Prop "justify-content" "flex-end" ]
1527+
1528+ Right ->
1529+ [ Prop "align-items" "flex-end" ]
1530+
1531+ Left ->
1532+ [ Prop "align-items" "flex-start" ]
1533+
1534+ CenterX ->
1535+ [ Prop "align-items" "center" ]
1536+
1537+ CenterY ->
1538+ [ Prop "justify-content" "center" ]
1539+ ]
1540+ , Descriptor (dot classes.page)
1541+ [ Prop "display" "block"
1542+ , Child (dot <| classes.any ++ ":first-child")
1543+ [ Prop "margin" "0 !important"
1544+ ]
1545+
1546+ -- clear spacing of any subsequent element if an element is float-left
1547+ , Child (dot <| classes.any ++ selfName (Self Left) ++ ":first-child + ." ++ classes.any)
1548+ [ Prop "margin" "0 !important"
1549+ ]
1550+ , Child (dot <| classes.any ++ selfName (Self Right) ++ ":first-child + ." ++ classes.any)
1551+ [ Prop "margin" "0 !important"
1552+ ]
1553+ , describeAlignment <|
1554+ \alignment ->
1555+ case alignment of
1556+ Top ->
1557+ ( []
1558+ , []
1559+ )
1560+
1561+ Bottom ->
1562+ ( []
1563+ , []
1564+ )
1565+
1566+ Right ->
1567+ ( []
1568+ , [ Prop "float" "right"
1569+ , Descriptor "::after"
1570+ [ Prop "content" "\"\""
1571+ , Prop "display" "table"
1572+ , Prop "clear" "both"
1573+ ]
1574+ ]
1575+ )
1576+
1577+ Left ->
1578+ ( []
1579+ , [ Prop "float" "left"
1580+ , Descriptor "::after"
1581+ [ Prop "content" "\"\""
1582+ , Prop "display" "table"
1583+ , Prop "clear" "both"
1584+ ]
1585+ ]
1586+ )
1587+
1588+ CenterX ->
1589+ ( []
1590+ , []
1591+ )
1592+
1593+ CenterY ->
1594+ ( []
1595+ , []
1596+ )
1597+ ]
1598+ , Descriptor (dot classes.inputMultiline)
1599+ [ Prop "white-space" "pre-wrap !important"
1600+ , Prop "height" "100%"
1601+ , Prop "width" "100%"
1602+ , Prop "background-color" "transparent"
1603+ ]
1604+ , Descriptor (dot classes.inputMultilineWrapper)
1605+ -- Get this.
1606+ -- This allows multiline input to anchor scrolling to the bottom of the node
1607+ -- when in a scrolling viewport, and the user is adding content.
1608+ -- however, it only works in chrome. In firefox, it prevents scrolling.
1609+ --
1610+ -- But how crazy is this solution?
1611+ -- [ Prop "display" "flex"
1612+ -- , Prop "flex-direction" "column-reverse"
1613+ -- ]
1614+ [ -- to increase specificity to beat another rule
1615+ Descriptor (dot classes.single)
1616+ [ Prop "flex-basis" "auto" ]
1617+ ]
1618+ , Descriptor (dot classes.inputMultilineParent)
1619+ [ Prop "white-space" "pre-wrap !important"
1620+ , Prop "cursor" "text"
1621+ , Child (dot classes.inputMultilineFiller)
1622+ [ Prop "white-space" "pre-wrap !important"
1623+ , Prop "color" "transparent"
1624+ ]
1625+ ]
1626+ , Descriptor (dot classes.paragraph)
1627+ [ Prop "display" "block"
1628+ , Prop "white-space" "normal"
1629+ , Prop "overflow-wrap" "break-word"
1630+ , Descriptor (dot classes.hasBehind)
1631+ [ Prop "z-index" "0"
1632+ , Child (dot classes.behind)
1633+ [ Prop "z-index" "-1"
1634+ ]
1635+ ]
1636+ , AllChildren (dot classes.text)
1637+ [ Prop "display" "inline"
1638+ , Prop "white-space" "normal"
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+ ]
1649+ , AllChildren (dot classes.single)
1650+ [ Prop "display" "inline"
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+ ]
1660+ , Descriptor (dot classes.inFront)
1661+ [ Prop "display" "flex"
1662+ ]
1663+ , Descriptor (dot classes.behind)
1664+ [ Prop "display" "flex"
1665+ ]
1666+ , Descriptor (dot classes.above)
1667+ [ Prop "display" "flex"
1668+ ]
1669+ , Descriptor (dot classes.below)
1670+ [ Prop "display" "flex"
1671+ ]
1672+ , Descriptor (dot classes.onRight)
1673+ [ Prop "display" "flex"
1674+ ]
1675+ , Descriptor (dot classes.onLeft)
1676+ [ Prop "display" "flex"
1677+ ]
1678+ , Child (dot classes.text)
1679+ [ Prop "display" "inline"
1680+ , Prop "white-space" "normal"
1681+ ]
1682+ ]
1683+ , Child (dot classes.row)
1684+ [ Prop "display" "inline"
1685+ ]
1686+ , Child (dot classes.column)
1687+ [ Prop "display" "inline-flex"
1688+ ]
1689+ , Child (dot classes.grid)
1690+ [ Prop "display" "inline-grid"
1691+ ]
1692+ , describeAlignment <|
1693+ \alignment ->
1694+ case alignment of
1695+ Top ->
1696+ ( []
1697+ , []
1698+ )
1699+
1700+ Bottom ->
1701+ ( []
1702+ , []
1703+ )
1704+
1705+ Right ->
1706+ ( []
1707+ , [ Prop "float" "right" ]
1708+ )
1709+
1710+ Left ->
1711+ ( []
1712+ , [ Prop "float" "left" ]
1713+ )
1714+
1715+ CenterX ->
1716+ ( []
1717+ , []
1718+ )
1719+
1720+ CenterY ->
1721+ ( []
1722+ , []
1723+ )
1724+ ]
1725+ , Descriptor ".hidden"
1726+ [ Prop "display" "none"
1727+ ]
1728+ , Descriptor (dot classes.textThin)
1729+ [ Prop "font-weight" "100"
1730+ ]
1731+ , Descriptor (dot classes.textExtraLight)
1732+ [ Prop "font-weight" "200"
1733+ ]
1734+ , Descriptor (dot classes.textLight)
1735+ [ Prop "font-weight" "300"
1736+ ]
1737+ , Descriptor (dot classes.textNormalWeight)
1738+ [ Prop "font-weight" "400"
1739+ ]
1740+ , Descriptor (dot classes.textMedium)
1741+ [ Prop "font-weight" "500"
1742+ ]
1743+ , Descriptor (dot classes.textSemiBold)
1744+ [ Prop "font-weight" "600"
1745+ ]
1746+ , Descriptor (dot classes.bold)
1747+ [ Prop "font-weight" "700"
1748+ ]
1749+ , Descriptor (dot classes.textExtraBold)
1750+ [ Prop "font-weight" "800"
1751+ ]
1752+ , Descriptor (dot classes.textHeavy)
1753+ [ Prop "font-weight" "900"
1754+ ]
1755+ , Descriptor (dot classes.italic)
1756+ [ Prop "font-style" "italic"
1757+ ]
1758+ , Descriptor (dot classes.strike)
1759+ [ Prop "text-decoration" "line-through"
1760+ ]
1761+ , Descriptor (dot classes.underline)
1762+ [ Prop "text-decoration" "underline"
1763+ , Prop "text-decoration-skip-ink" "auto"
1764+ , Prop "text-decoration-skip" "ink"
1765+ ]
1766+ , Descriptor (dot classes.underline ++ dot classes.strike)
1767+ [ Prop "text-decoration" "line-through underline"
1768+ , Prop "text-decoration-skip-ink" "auto"
1769+ , Prop "text-decoration-skip" "ink"
1770+ ]
1771+ , Descriptor (dot classes.textUnitalicized)
1772+ [ Prop "font-style" "normal"
1773+ ]
1774+ , Descriptor (dot classes.textJustify)
1775+ [ Prop "text-align" "justify"
1776+ ]
1777+ , Descriptor (dot classes.textJustifyAll)
1778+ [ Prop "text-align" "justify-all"
1779+ ]
1780+ , Descriptor (dot classes.textCenter)
1781+ [ Prop "text-align" "center"
1782+ ]
1783+ , Descriptor (dot classes.textRight)
1784+ [ Prop "text-align" "right"
1785+ ]
1786+ , Descriptor (dot classes.textLeft)
1787+ [ Prop "text-align" "left"
1788+ ]
1789+ , Descriptor ".modal"
1790+ [ Prop "position" "fixed"
1791+ , Prop "left" "0"
1792+ , Prop "top" "0"
1793+ , Prop "width" "100%"
1794+ , Prop "height" "100%"
1795+ , Prop "pointer-events" "none"
1796+ ]
1797+ ]
1798+ ]
deps/elm-ui/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;
deps/elm-ui/tests-rendering/automation/doc-preview.shnew file+1
@@ -0,0 +1 @@
1+elm make --docs docs.json
deps/elm-ui/tests-rendering/automation/publish-file.shnew file+31
@@ -0,0 +1,31 @@
1+# These env variables need to be set before running this script
2+# FILE="test.html"
3+# BUILD="1.1.0"
4+# NAME="development"
5+DIRECTORY='elm-ui-testing'
6+
7+# Check to see if the repo is already cloned locally
8+cd tmp
9+if [ ! -d "$DIRECTORY" ]; then
10+ git clone git@github.com:mdgriffith/elm-ui-testing.git
11+else
12+ git pull
13+fi
14+mkdir -p "$DIRECTORY/public/tests/$BUILD/$NAME/"
15+cp "$FILE" "$DIRECTORY/public/tests/$BUILD/$NAME/index.html"
16+if [ -z "$(git status --porcelain)" ]; then
17+ # Working directory clean
18+ echo "No changes need for $BUILD -> $NAME"
19+else
20+ cd "$DIRECTORY"
21+ # Uncommitted changes
22+ git config --global user.email "$GIT_EMAIL"
23+ git config --global user.name "$GIT_NAME"
24+ git add .
25+ git commit -m "Elm UI test for $NAME on $BUILD"
26+ git push origin master
27+
28+ echo "Files published for for $BUILD -> $NAME"
29+fi
30+
31+
deps/elm-ui/tests-rendering/automation/run.jsnew file+304
@@ -0,0 +1,304 @@
1+const { Builder, By, Key, until } = require("selenium-webdriver");
2+const chrome = require("selenium-webdriver/chrome");
3+const firefox = require("selenium-webdriver/firefox");
4+const fs = require("fs");
5+const program = require("commander");
6+const path = require("path");
7+const chalk = require("chalk");
8+const childProcess = require("child_process");
9+const compile_and_embed = require("./build.js").compile_and_embed;
10+
11+program
12+ .option("-s, --sauce", "run tests on sauce labs")
13+ .option("--chrome", "run chrome tests (default)")
14+ .option("--firefox", "run firefox tests")
15+ .option("--ie", "run ie tests")
16+ .option("--edge", "run edge tests")
17+ .option("--build [value]", "Set build number for sauce labs")
18+ .option("--name [value]", "Set run name for sauce labs")
19+ .option("--verbose", "Print out all test results")
20+ .option("--headless", "run tests without showing the browser")
21+ .parse(process.argv);
22+
23+// 'Windows 10'
24+
25+const windows = {
26+ chrome: {
27+ platform: "Windows 10",
28+ browser: "chrome",
29+ browserVersion: "latest",
30+ },
31+ firefox: {
32+ platform: "Windows 10",
33+ browser: "firefox",
34+ browserVersion: "latest",
35+ },
36+ edge: {
37+ platform: "Windows 10",
38+ browser: "MicrosoftEdge",
39+ browserVersion: "latest",
40+ },
41+ ie: {
42+ platform: "Windows 10",
43+ browser: "internet explorer",
44+ browserVersion: "latest",
45+ },
46+};
47+
48+const all_windows = [
49+ windows.chrome,
50+ windows.firefox,
51+ windows.edge,
52+ // i.e. takes forever and seems to make selenium timeout :/
53+ // not really sure how to extend the timeout.
54+ // , windows.ie
55+];
56+
57+// "macOS 10.14"
58+const osx = {
59+ chrome: {
60+ platform: "macOS 10.14",
61+ browser: "chrome",
62+ browserVersion: "latest",
63+ },
64+ firefox: {
65+ platform: "macOS 10.14",
66+ browser: "firefox",
67+ browserVersion: "latest",
68+ },
69+ safari: {
70+ platform: "macOS 10.14",
71+ browser: "safari",
72+ browserVersion: "latest",
73+ },
74+};
75+
76+const all_osx = [osx.safari];
77+
78+const all_browsers = all_windows.concat(all_osx);
79+
80+function prepare_all_envs(config) {
81+ var envs = [];
82+
83+ for (i = 0; i < all_browsers.length; i++) {
84+ envs.push({
85+ browser: all_browsers[i].browser,
86+ browserVersion: all_browsers[i].browserVersion,
87+ platform: all_browsers[i].platform,
88+ build: config.build,
89+ name: config.name,
90+ });
91+ }
92+
93+ // for (i = 0; i < osx.length; i++) {
94+ // envs.push({
95+ // browser: osx[i].browser,
96+ // browserVersion: osx[i].browserVersion,
97+ // platform: "macOS 10.14",
98+ // build: config.build,
99+ // name: config.name,
100+ // });
101+ // }
102+
103+ return envs;
104+}
105+
106+function prepare_sauce_driver(env) {
107+ const username = process.env.SAUCE_USERNAME;
108+ const accessKey = process.env.SAUCE_ACCESS_KEY;
109+
110+ driver = new Builder()
111+ .withCapabilities({
112+ browserName: env.browser,
113+ platformName: env.platform,
114+ browserVersion: env.browserVersion,
115+ /* Pass Sauce User Name and Access Key */
116+ "sauce:options": {
117+ username: username,
118+ accessKey: accessKey,
119+ build: env.build,
120+ name: env.name,
121+ },
122+ })
123+ .usingServer("https://@ondemand.saucelabs.com:443/wd/hub")
124+ .build();
125+
126+ return driver;
127+}
128+
129+async function prepare_local_driver(env) {
130+ const firefoxOptions = new firefox.Options();
131+ const chromeOptions = new chrome.Options();
132+
133+ if (program.headless) {
134+ firefoxOptions.headless();
135+ chromeOptions.headless();
136+ }
137+
138+ let driver = await new Builder()
139+ .forBrowser(env.browser)
140+ .setChromeOptions(chromeOptions)
141+ .setFirefoxOptions(firefoxOptions)
142+ .build();
143+
144+ return driver;
145+}
146+
147+async function run_test(driver, url) {
148+ var results = null;
149+ try {
150+ await driver
151+ .manage()
152+ .window()
153+ .setRect({ width: 1200, height: 800, x: 0, y: 0 });
154+ await driver.get(url);
155+ await driver.wait(until.titleIs("tests finished"), 240 * 1000);
156+ results = await driver.executeScript("return test_results");
157+ } finally {
158+ await driver.quit();
159+ }
160+ return results;
161+}
162+
163+(async () => {
164+ var dir = "tmp";
165+ if (!fs.existsSync(dir)) {
166+ fs.mkdirSync(dir);
167+ }
168+ console.log("Compiling tests");
169+ await compile_and_embed({
170+ template: "./tests-rendering/automation/templates/gather-styles.html",
171+ target: "./tmp/test.html",
172+ elm: "src/Tests/All.elm",
173+ elmOptions: { cwd: "./tests-rendering" },
174+ });
175+ console.log("Done compiling");
176+
177+ if (program.sauce) {
178+ const build = program.build;
179+ const name = program.name;
180+
181+ if (build == null || name == null) {
182+ throw "A Build and a Name must be specified.";
183+ }
184+
185+ var results = [];
186+
187+ // Publish to netlify
188+ childProcess.execSync("sh tests-rendering/automation/publish-file.sh", {
189+ env: {
190+ FILE: "test.html",
191+ BUILD: program.build,
192+ NAME: program.name,
193+ GIT_EMAIL: "automation@elm-ui.com",
194+ GIT_NAME: "Elm UI Automation",
195+ HOME: process.env.HOME,
196+ SSH_AUTH_SOCK: process.env.SSH_AUTH_SOCK,
197+ SSH_AGENT_PID: process.env.SSH_AGENT_PID,
198+ },
199+ });
200+
201+ var url = `http://elm-ui-testing.netlify.com/tests/${program.build}/${program.name}/`;
202+ console.log(`Running sauce labs test:`);
203+ console.log(` ${url}`);
204+
205+ const envs = prepare_all_envs({ build: build, name: name });
206+ console.log(envs);
207+ var test_runs = [];
208+ var test_labels = [];
209+ for (i = 0; i < envs.length; i++) {
210+ var driver = prepare_sauce_driver(envs[i]);
211+ test_runs.push(run_test(driver, url));
212+ test_labels.push(envs[i]);
213+ }
214+ var results = await Promise.all(test_runs);
215+ for (i = 0; i < results.length; i++) {
216+ print_results(renderEnvName(test_labels[i]), results[i]);
217+ }
218+ } else {
219+ // Run chrome if nothing else is selected
220+ if (program.chrome || (!program.chrome && !program.firefox)) {
221+ console.log("Running locally on Chrome...");
222+ const driver = await prepare_local_driver(osx.chrome);
223+ var results = await run_test(
224+ driver,
225+ "file://" + path.resolve("./tmp/test.html")
226+ );
227+ print_results("Local Chrome", results);
228+ }
229+ if (program.firefox) {
230+ console.log("Running locally on Firefox...");
231+ const driver = await prepare_local_driver(osx.firefox);
232+ var results = await run_test(
233+ driver,
234+ "file://" + path.resolve("./tmp/test.html")
235+ );
236+ print_results("Local Firefox", results);
237+ }
238+ if (program.ie) {
239+ console.log("Running locally on IE...");
240+ const driver = await prepare_local_driver(windows.ie);
241+ var results = await run_test(
242+ driver,
243+ "file://" + path.resolve("./tmp/test.html")
244+ );
245+ print_results("Local IE", results);
246+ }
247+ if (program.edge) {
248+ console.log("Running locally on Edge...");
249+ const driver = await prepare_local_driver(windows.edge);
250+ var results = await run_test(
251+ driver,
252+ "file://" + path.resolve("./tmp/test.html")
253+ );
254+ print_results("Local Edge", results);
255+ }
256+ }
257+})();
258+
259+function renderEnvName(env) {
260+ return `${env.platform}, ${env.browser} ${env.browserVersion}`;
261+}
262+
263+function print_results(label, tests) {
264+ var total_passed = 0;
265+ var total_failed = 0;
266+ var i;
267+ if (program.verbose) {
268+ console.log(label);
269+ }
270+ for (i = 0; i < tests.length; i++) {
271+ var passed = 0;
272+ var failed = 0;
273+ for (j = 0; j < tests[i].results.length; j++) {
274+ if (tests[i].results[j].passing) {
275+ passed = passed + 1;
276+ } else {
277+ if (failed == 0) {
278+ if (!program.verbose) {
279+ console.log(label);
280+ }
281+ console.log(tests[i].label);
282+ }
283+ failed = failed + 1;
284+ console.log(" " + chalk.red("fail") + " ->");
285+ console.log(" " + tests[i].results[j].description);
286+ }
287+ }
288+ total_passed = total_passed + passed;
289+ total_failed = total_failed + failed;
290+
291+ if (failed != 0) {
292+ console.log(chalk.green(` ${passed} tests passed`));
293+ console.log(chalk.red(` ${failed} tests failed`));
294+ console.log();
295+ } else if (program.verbose) {
296+ console.log(tests[i].label + chalk.green(` ${passed} tests passed`));
297+ }
298+ }
299+ if (total_failed == 0) {
300+ console.log(
301+ `${label} -> ` + chalk.green(`All ${total_passed} tests passed`)
302+ );
303+ }
304+}
deps/elm-ui/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+ ]
deps/elm-ui/tests-rendering/automation/templates/gather-styles.htmlnew file+185
@@ -0,0 +1,185 @@
1+<!DOCTYPE html>
2+<html>
3+ <head>
4+ <meta charset="UTF-8" />
5+ <title>Elm UI Rendering Test</title>
6+ <script>
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+ }
129+ </script>
130+ </head>
131+ <style></style>
132+ <body id="root">
133+ <body id="root">
134+ <div id="elm-home"></div>
135+ <canvas id="canvas"></canvas>
136+ </body>
137+ </body>
138+
139+ <script type="text/javascript">
140+ // Starting Elm App,
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");
147+
148+ var test_results = "waiting..";
149+
150+ app.ports.report.subscribe(function (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";
155+ });
156+
157+ app.ports.analyze.subscribe(function (ids) {
158+ // ids : List String
159+ var idsLength = ids.length;
160+ var results = [];
161+ for (var i = 0; i < idsLength; i++) {
162+ var id = ids[i];
163+ var element = document.getElementById(id);
164+ if (element == null) {
165+ console.log("id " + id + " not found");
166+ }
167+ var style = getStyle(element);
168+ var bbox = getBoundingBox(element);
169+ var metrics = getTextMetrics(element);
170+
171+ var visible = isVisible(id, bbox);
172+
173+ var result = {
174+ textMetrics: metrics,
175+ bbox: bbox,
176+ style: style,
177+ id: id,
178+ isVisible: visible,
179+ };
180+ results.push(result);
181+ }
182+ app.ports.styles.send(results);
183+ });
184+ </script>
185+</html>
deps/elm-ui/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+})();
deps/elm-ui/tests-rendering/cases/Manual/AlignedForm.elmnew file+286

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/Manual/All.elmnew file+1263

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/Manual/LazyPerformance.elmnew file+523

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/Manual/OtherScrollbars.elmnew file+36

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/Manual/Overflow.elmnew file+16

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/Manual/Scrollbars.elmnew file+62

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/Manual/ScrollbarsPls.elmnew file+58

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/Manual/TextLayout.elmnew file+43

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/elm.jsonnew file+23

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/open/InFrontSize.elmnew file+43

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/open/LabelledInputAlignRight.elmnew file+28

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/open/NearbyElementBordersOverlap.elmnew file+46

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/open/Scrollbar2.elmnew file+39

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/open/Scrollbars.elmnew file+50

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/open/StackedScrollingColumnsHeight.elmnew file+42

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/open/WeirdCentering.elmnew file+35

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Adjusted.elmnew file+70

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/BehindContent.elmnew file+34

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/ClippedElInFixedWidthColumn.elmnew file+31

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/ColumnGrowth.elmnew file+40

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/ElInFixedHeightColumn.elmnew file+41

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/FocusStyles.elmnew file+34

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/HugePlaceholder.elmnew file+25

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Images/ImageRegression.elmnew file+63

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Images/ImageRegression2.elmnew file+19

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Images/ImageSizing.elmnew file+24

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Input/FocusLinks.elmnew file+37

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Input/FocusStylePrecedingElements.elmnew file+38

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Input/InputAlignment.elmnew file+44

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Input/LabelAlignBaseline.elmnew file+34

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Input/Placeholder.elmnew file+59

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Input/Slider.elmnew file+74

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Layout/BreaksWithinParagraph.elmnew file+17

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Layout/ColumnLayouts.elmnew file+103

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Layout/Columns/DistributeHeight.elmnew file+46

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Layout/Columns/DistributeHeightCorrectly2.elmnew file+86

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Layout/Columns/DoNotCollapseBelow0.elmnew file+48

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Layout/Columns/SafariTwo.elmnew file+40

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Layout/NestedParagraphs.elmnew file+165

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Layout/Rounded.elmnew file+54

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Layout/SafariBugIssue147.elmnew file+37

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Layout/WrapRow.elmnew file+13

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Misc/Scroll.elmnew file+48

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/MismatchTextInputText.elmnew file+82

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/MultilineCollapsed.elmnew file+61

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/MultilineInput.elmnew file+377

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/MultilineNewline.elmnew file+61

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Nearby/InFrontIssue.elmnew file+64

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Nearby/Issue22ZIndex.elmnew file+87

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Nearby/OtherInFrontIssue.elmnew file+55

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/Nearby/ZIndexRegression.elmnew file+43

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/NestedColumns.elmnew file+33

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/OtherOtherZindex.elmnew file+31

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/OtherZIndex.elmnew file+85

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/OverflowingInput.elmnew file+48

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/OverflowingInput2.elmnew file+54

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/OverflowingInput3.elmnew file+95

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/ReversedTableOrder.elmnew file+56

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/TextAreaMax.elmnew file+80

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/WeirdWrapping.elmnew file+32

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/ZIndex.elmnew file+56

This diff is too big to show here.

deps/elm-ui/tests-rendering/cases/resolved/elm.jsonnew file+25

This diff is too big to show here.

deps/elm-ui/tests-rendering/elm.jsonnew file+25

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Generator.elmnew file+53

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Testable.elmnew file+940

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Testable/Element.elmnew file+1723

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Testable/Element/Background.elmnew file+28

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Testable/Element/Border.elmnew file+20

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Testable/Element/Font.elmnew file+56

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Testable/Generator.elmnew file+398

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Testable/Runner.elmnew file+607

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Tests/Alignment.elmnew file+49

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Tests/All.elmnew file+44

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Tests/Nearby.elmnew file+179

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Tests/Palette.elmnew file+45

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Tests/Run.elmnew file+14

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Tests/Spacing.elmnew file+36

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Tests/Table.elm.todonew file+123

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Tests/TextWrapping.elmnew file+51

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Tests/Transparency.elmnew file+57

This diff is too big to show here.

deps/elm-ui/tests-rendering/src/Tests/WidthHeight.elmnew file+61

This diff is too big to show here.

deps/elm-ui/tests/ClassNames.elmnew file+172

This diff is too big to show here.

deps/elm-ui/tests/Flags.elmnew file+78

This diff is too big to show here.

deps/elm-ui/yarn.locknew file+1271

This diff is too big to show here.

elm-pages.config.mjs+1

This diff is too big to show here.

elm.json+2−2

This diff is too big to show here.

public/NotoSans.ttfnew file

Binary file not shown.

public/Unbounded.ttfnew file

Binary file not shown.

style.css+24−3

This diff is too big to show here.