@@ -0,0 +1,2847 @@
1+module Internal.Model exposing (..)
2+
3+{-| -}
4+
5+import Html
6+import Html.Attributes
7+import Html.Keyed
8+import Internal.Flag as Flag exposing (Flag)
9+import Internal.Style exposing (classes, dot)
10+import Json.Encode as Json
11+import Set exposing (Set)
12+import VirtualDom
13+
14+
15+type Element msg
16+ = Unstyled (LayoutContext -> VirtualDom.Node msg)
17+ | Styled
18+ { styles : List Style
19+ , html : EmbedStyle -> LayoutContext -> VirtualDom.Node msg
20+ }
21+ | Text String
22+ | Empty
23+
24+
25+type EmbedStyle
26+ = NoStyleSheet
27+ | StaticRootAndDynamic OptionRecord (List Style)
28+ | OnlyDynamic OptionRecord (List Style)
29+
30+
31+noStyleSheet : EmbedStyle
32+noStyleSheet =
33+ NoStyleSheet
34+
35+
36+type LayoutContext
37+ = AsRow
38+ | AsColumn
39+ | AsEl
40+ | AsGrid
41+ | AsParagraph
42+ | AsTextColumn
43+
44+
45+type Aligned
46+ = Unaligned
47+ | Aligned (Maybe HAlign) (Maybe VAlign)
48+
49+
50+type HAlign
51+ = Left
52+ | CenterX
53+ | Right
54+
55+
56+type VAlign
57+ = Top
58+ | CenterY
59+ | Bottom
60+
61+
62+type Style
63+ = Style String (List Property)
64+ -- class prop val
65+ | FontFamily String (List Font)
66+ | FontSize Int
67+ -- classname, prop, value
68+ | Single String String String
69+ | Colored String String Color
70+ | SpacingStyle String Int Int
71+ | PaddingStyle String Int Int Int Int
72+ | GridTemplateStyle
73+ { spacing : ( Length, Length )
74+ , columns : List Length
75+ , rows : List Length
76+ }
77+ | GridPosition
78+ { row : Int
79+ , col : Int
80+ , width : Int
81+ , height : Int
82+ }
83+ | Transform Transformation
84+ | PseudoSelector PseudoClass (List Style)
85+ | Transparency String Float
86+ | Shadows String String
87+
88+
89+type Transformation
90+ = Untransformed
91+ | Moved XYZ
92+ -- translate, scale, rotate
93+ | FullTransform XYZ XYZ XYZ Angle
94+
95+
96+type PseudoClass
97+ = Focus
98+ | Hover
99+ | Active
100+
101+
102+type Font
103+ = Serif
104+ | SansSerif
105+ | Monospace
106+ | Typeface String
107+ | ImportFont String String
108+
109+
110+type Property
111+ = Property String String
112+
113+
114+type alias XYZ =
115+ ( Float, Float, Float )
116+
117+
118+type alias Angle =
119+ Float
120+
121+
122+type Attribute aligned msg
123+ = NoAttribute
124+ | Attr (VirtualDom.Attribute msg)
125+ | Describe Description
126+ -- invalidation key and literal class
127+ | Class Flag String
128+ -- invalidation key "border-color" as opposed to "border-color-10-10-10" that will be the key for the class
129+ | StyleClass Flag Style
130+ | AlignY VAlign
131+ | AlignX HAlign
132+ | Width Length
133+ | Height Length
134+ | Nearby Location (Element msg)
135+ | TransformComponent Flag TransformComponent
136+
137+
138+type TransformComponent
139+ = MoveX Float
140+ | MoveY Float
141+ | MoveZ Float
142+ | MoveXYZ XYZ
143+ | Rotate XYZ Float
144+ | Scale XYZ
145+
146+
147+type Description
148+ = Main
149+ | Navigation
150+ -- | Search
151+ | ContentInfo
152+ | Complementary
153+ | Heading Int
154+ | Label String
155+ | LivePolite
156+ | LiveAssertive
157+ | Button
158+ | Paragraph
159+
160+
161+type Length
162+ = Px Int
163+ | Content
164+ | Fill Int
165+ | Min Int Length
166+ | Max Int Length
167+
168+
169+type Axis
170+ = XAxis
171+ | YAxis
172+ | AllAxis
173+
174+
175+type Location
176+ = Above
177+ | Below
178+ | OnRight
179+ | OnLeft
180+ | InFront
181+ | Behind
182+
183+
184+{-| -}
185+type Color
186+ = Rgba Float Float Float Float
187+
188+
189+type NodeName
190+ = Generic
191+ | NodeName String
192+ | Embedded String String
193+
194+
195+div =
196+ Generic
197+
198+
199+type alias Gathered msg =
200+ { node : NodeName
201+ , attributes : List (VirtualDom.Attribute msg)
202+ , styles : List Style
203+ , children : List (VirtualDom.Node msg)
204+ , has : Flag.Field
205+ }
206+
207+
208+htmlClass : String -> Attribute aligned msg
209+htmlClass cls =
210+ Attr <| Html.Attributes.class cls
211+
212+
213+{-| -}
214+unstyled : VirtualDom.Node msg -> Element msg
215+unstyled =
216+ Unstyled << always
217+
218+
219+finalizeNode has node attributes children embedMode parentContext =
220+ let
221+ createNode nodeName attrs =
222+ case children of
223+ Keyed keyed ->
224+ VirtualDom.keyedNode nodeName
225+ attrs
226+ (case embedMode of
227+ NoStyleSheet ->
228+ keyed
229+
230+ OnlyDynamic opts styles ->
231+ embedKeyed False opts styles keyed
232+
233+ StaticRootAndDynamic opts styles ->
234+ embedKeyed True opts styles keyed
235+ )
236+
237+ Unkeyed unkeyed ->
238+ (case nodeName of
239+ "div" ->
240+ Html.div
241+
242+ "p" ->
243+ Html.p
244+
245+ _ ->
246+ VirtualDom.node nodeName
247+ )
248+ attrs
249+ (case embedMode of
250+ NoStyleSheet ->
251+ unkeyed
252+
253+ OnlyDynamic opts styles ->
254+ embedWith False opts styles unkeyed
255+
256+ StaticRootAndDynamic opts styles ->
257+ embedWith True opts styles unkeyed
258+ )
259+
260+ html =
261+ case node of
262+ Generic ->
263+ createNode "div" attributes
264+
265+ NodeName nodeName ->
266+ createNode nodeName attributes
267+
268+ Embedded nodeName internal ->
269+ VirtualDom.node nodeName
270+ attributes
271+ [ createNode internal [ Html.Attributes.class (classes.any ++ " " ++ classes.single) ]
272+ ]
273+ in
274+ case parentContext of
275+ AsRow ->
276+ if Flag.present Flag.widthFill has && not (Flag.present Flag.widthBetween has) then
277+ html
278+ else if Flag.present Flag.alignRight has then
279+ Html.u
280+ [ Html.Attributes.class
281+ (String.join " "
282+ [ classes.any
283+ , classes.single
284+ , classes.container
285+ , classes.contentCenterY
286+ , classes.alignContainerRight
287+ ]
288+ )
289+ ]
290+ [ html ]
291+ else if Flag.present Flag.centerX has then
292+ Html.s
293+ [ Html.Attributes.class
294+ (String.join " "
295+ [ classes.any
296+ , classes.single
297+ , classes.container
298+ , classes.contentCenterY
299+ , classes.alignContainerCenterX
300+ ]
301+ )
302+ ]
303+ [ html ]
304+ else
305+ html
306+
307+ AsColumn ->
308+ if Flag.present Flag.heightFill has && not (Flag.present Flag.heightBetween has) then
309+ html
310+ else if Flag.present Flag.centerY has then
311+ Html.s
312+ [ Html.Attributes.class
313+ (String.join " "
314+ [ classes.any
315+ , classes.single
316+ , classes.container
317+ , classes.alignContainerCenterY
318+ ]
319+ )
320+ ]
321+ [ html ]
322+ else if Flag.present Flag.alignBottom has then
323+ Html.u
324+ [ Html.Attributes.class
325+ (String.join " "
326+ [ classes.any
327+ , classes.single
328+ , classes.container
329+ , classes.alignContainerBottom
330+ ]
331+ )
332+ ]
333+ [ html ]
334+ else
335+ html
336+
337+ _ ->
338+ html
339+
340+
341+embedWith static opts styles children =
342+ if static then
343+ staticRoot
344+ :: (styles
345+ |> List.foldl reduceStyles ( Set.empty, [ renderFocusStyle opts.focus ] )
346+ |> Tuple.second
347+ -- |> reduceStylesRecursive Set.empty [ ]) --renderFocusStyle opts.focus ]
348+ -- |> sortedReduce
349+ |> toStyleSheet opts
350+ )
351+ :: children
352+ else
353+ (styles
354+ |> List.foldl reduceStyles ( Set.empty, [ renderFocusStyle opts.focus ] )
355+ |> Tuple.second
356+ -- |> reduceStylesRecursive Set.empty [ ]) --renderFocusStyle opts.focus ]
357+ -- |> sortedReduce
358+ |> toStyleSheet opts
359+ )
360+ :: children
361+
362+
363+embedKeyed static opts styles children =
364+ if static then
365+ ( "static-stylesheet", staticRoot )
366+ :: ( "dynamic-stylesheet"
367+ , styles
368+ |> List.foldl reduceStyles ( Set.empty, [ renderFocusStyle opts.focus ] )
369+ |> Tuple.second
370+ -- |> reduceStylesRecursive Set.empty [ ]) --renderFocusStyle opts.focus ]
371+ -- |> sortedReduce
372+ |> toStyleSheet opts
373+ )
374+ :: children
375+ else
376+ ( "dynamic-stylesheet"
377+ , styles
378+ |> List.foldl reduceStyles ( Set.empty, [ renderFocusStyle opts.focus ] )
379+ |> Tuple.second
380+ -- |> reduceStylesRecursive Set.empty [ ]) --renderFocusStyle opts.focus ]
381+ -- |> sortedReduce
382+ |> toStyleSheet opts
383+ )
384+ :: children
385+
386+
387+reduceStylesRecursive : Set String -> List Style -> List Style -> List Style
388+reduceStylesRecursive cache found styles =
389+ case styles of
390+ [] ->
391+ found
392+
393+ head :: remaining ->
394+ let
395+ styleName =
396+ getStyleName head
397+ in
398+ if Set.member styleName cache then
399+ reduceStylesRecursive cache found remaining
400+ else
401+ reduceStylesRecursive (Set.insert styleName cache) (head :: found) remaining
402+
403+
404+reduceStyles : Style -> ( Set String, List Style ) -> ( Set String, List Style )
405+reduceStyles style (( cache, existing ) as nevermind) =
406+ let
407+ styleName =
408+ getStyleName style
409+ in
410+ if Set.member styleName cache then
411+ nevermind
412+ else
413+ ( Set.insert styleName cache
414+ , style :: existing
415+ )
416+
417+
418+sortedReduce styles =
419+ styles
420+ -- |> List.map (\x -> ( getStyleName x, x ))
421+ |> List.sortBy getStyleName
422+ |> reduceRecursiveCalcName []
423+
424+
425+reduceRecursiveCalcName : List Style -> List Style -> List Style
426+reduceRecursiveCalcName found styles =
427+ case styles of
428+ [] ->
429+ found
430+
431+ headOfList :: [] ->
432+ headOfList :: found
433+
434+ headOfList :: other :: remaining ->
435+ if headOfList /= other then
436+ reduceRecursiveCalcName (headOfList :: found) (other :: remaining)
437+ else
438+ reduceRecursiveCalcName found (other :: remaining)
439+
440+
441+reduceRecursive : List Style -> List ( String, Style ) -> List Style
442+reduceRecursive found styles =
443+ case styles of
444+ [] ->
445+ found
446+
447+ ( _, headOfList ) :: [] ->
448+ headOfList :: found
449+
450+ ( headOfListName, headOfList ) :: ( otherName, other ) :: remaining ->
451+ if headOfListName /= otherName then
452+ reduceRecursive (headOfList :: found) (( otherName, other ) :: remaining)
453+ else
454+ reduceRecursive found (( otherName, other ) :: remaining)
455+
456+
457+addNodeName : String -> NodeName -> NodeName
458+addNodeName newNode old =
459+ case old of
460+ Generic ->
461+ NodeName newNode
462+
463+ NodeName name ->
464+ Embedded name newNode
465+
466+ Embedded x y ->
467+ Embedded x y
468+
469+
470+alignXName : HAlign -> String
471+alignXName align =
472+ case align of
473+ Left ->
474+ classes.alignedHorizontally ++ " " ++ classes.alignLeft
475+
476+ Right ->
477+ classes.alignedHorizontally ++ " " ++ classes.alignRight
478+
479+ CenterX ->
480+ classes.alignedHorizontally ++ " " ++ classes.alignCenterX
481+
482+
483+alignYName : VAlign -> String
484+alignYName align =
485+ case align of
486+ Top ->
487+ classes.alignedVertically ++ " " ++ classes.alignTop
488+
489+ Bottom ->
490+ classes.alignedVertically ++ " " ++ classes.alignBottom
491+
492+ CenterY ->
493+ classes.alignedVertically ++ " " ++ classes.alignCenterY
494+
495+
496+transformClass transform =
497+ case transform of
498+ Untransformed ->
499+ Nothing
500+
501+ Moved ( x, y, z ) ->
502+ Just <|
503+ "mv-"
504+ ++ floatClass x
505+ ++ "-"
506+ ++ floatClass y
507+ ++ "-"
508+ ++ floatClass z
509+
510+ FullTransform ( tx, ty, tz ) ( sx, sy, sz ) ( ox, oy, oz ) angle ->
511+ Just <|
512+ "tfrm-"
513+ ++ floatClass tx
514+ ++ "-"
515+ ++ floatClass ty
516+ ++ "-"
517+ ++ floatClass tz
518+ ++ "-"
519+ ++ floatClass sx
520+ ++ "-"
521+ ++ floatClass sy
522+ ++ "-"
523+ ++ floatClass sz
524+ ++ "-"
525+ ++ floatClass ox
526+ ++ "-"
527+ ++ floatClass oy
528+ ++ "-"
529+ ++ floatClass oz
530+ ++ "-"
531+ ++ floatClass angle
532+
533+
534+transformValue transform =
535+ case transform of
536+ Untransformed ->
537+ Nothing
538+
539+ Moved ( x, y, z ) ->
540+ Just <|
541+ "translate3d("
542+ ++ String.fromFloat x
543+ ++ "px, "
544+ ++ String.fromFloat y
545+ ++ "px, "
546+ ++ String.fromFloat z
547+ ++ "px)"
548+
549+ FullTransform ( tx, ty, tz ) ( sx, sy, sz ) ( ox, oy, oz ) angle ->
550+ let
551+ translate =
552+ "translate3d("
553+ ++ String.fromFloat tx
554+ ++ "px, "
555+ ++ String.fromFloat ty
556+ ++ "px, "
557+ ++ String.fromFloat tz
558+ ++ "px)"
559+
560+ scale =
561+ "scale3d("
562+ ++ String.fromFloat sx
563+ ++ ", "
564+ ++ String.fromFloat sy
565+ ++ ", "
566+ ++ String.fromFloat sz
567+ ++ ")"
568+
569+ rotate =
570+ "rotate3d("
571+ ++ String.fromFloat ox
572+ ++ ", "
573+ ++ String.fromFloat oy
574+ ++ ", "
575+ ++ String.fromFloat oz
576+ ++ ", "
577+ ++ String.fromFloat angle
578+ ++ "rad)"
579+ in
580+ Just <| translate ++ " " ++ scale ++ " " ++ rotate
581+
582+
583+composeTransformation transform component =
584+ case transform of
585+ Untransformed ->
586+ case component of
587+ MoveX x ->
588+ Moved ( x, 0, 0 )
589+
590+ MoveY y ->
591+ Moved ( 0, y, 0 )
592+
593+ MoveZ z ->
594+ Moved ( 0, 0, z )
595+
596+ MoveXYZ xyz ->
597+ Moved xyz
598+
599+ Rotate xyz angle ->
600+ FullTransform ( 0, 0, 0 ) ( 1, 1, 1 ) xyz angle
601+
602+ Scale xyz ->
603+ FullTransform ( 0, 0, 0 ) xyz ( 0, 0, 1 ) 0
604+
605+ Moved (( x, y, z ) as moved) ->
606+ case component of
607+ MoveX newX ->
608+ Moved ( newX, y, z )
609+
610+ MoveY newY ->
611+ Moved ( x, newY, z )
612+
613+ MoveZ newZ ->
614+ Moved ( x, y, newZ )
615+
616+ MoveXYZ xyz ->
617+ Moved xyz
618+
619+ Rotate xyz angle ->
620+ FullTransform moved ( 1, 1, 1 ) xyz angle
621+
622+ Scale scale ->
623+ FullTransform moved scale ( 0, 0, 1 ) 0
624+
625+ FullTransform (( x, y, z ) as moved) scaled origin angle ->
626+ case component of
627+ MoveX newX ->
628+ FullTransform ( newX, y, z ) scaled origin angle
629+
630+ MoveY newY ->
631+ FullTransform ( x, newY, z ) scaled origin angle
632+
633+ MoveZ newZ ->
634+ FullTransform ( x, y, newZ ) scaled origin angle
635+
636+ MoveXYZ newMove ->
637+ FullTransform newMove scaled origin angle
638+
639+ Rotate newOrigin newAngle ->
640+ FullTransform moved scaled newOrigin newAngle
641+
642+ Scale newScale ->
643+ FullTransform moved newScale origin angle
644+
645+
646+skippable flag style =
647+ if flag == Flag.borderWidth then
648+ case style of
649+ Single _ _ val ->
650+ case val of
651+ "0px" ->
652+ True
653+
654+ "1px" ->
655+ True
656+
657+ "2px" ->
658+ True
659+
660+ "3px" ->
661+ True
662+
663+ "4px" ->
664+ True
665+
666+ "5px" ->
667+ True
668+
669+ "6px" ->
670+ True
671+
672+ _ ->
673+ False
674+
675+ _ ->
676+ False
677+ else
678+ case style of
679+ FontSize i ->
680+ i >= 8 && i <= 32
681+
682+ PaddingStyle name t r b l ->
683+ t == b && t == r && t == l && t >= 0 && t <= 24
684+
685+ -- SpacingStyle _ _ _ ->
686+ -- True
687+ -- FontFamily _ _ ->
688+ -- True
689+ _ ->
690+ False
691+
692+
693+gatherAttrRecursive : String -> NodeName -> Flag.Field -> Transformation -> List Style -> List (VirtualDom.Attribute msg) -> List (VirtualDom.Node msg) -> List (Attribute aligned msg) -> Gathered msg
694+gatherAttrRecursive classes node has transform styles attrs children elementAttrs =
695+ case elementAttrs of
696+ [] ->
697+ case transformClass transform of
698+ Nothing ->
699+ { attributes = Html.Attributes.class classes :: attrs
700+ , styles = styles
701+ , node = node
702+ , children = children
703+ , has = has
704+ }
705+
706+ Just class ->
707+ { attributes = Html.Attributes.class (classes ++ " " ++ class) :: attrs
708+ , styles = Transform transform :: styles
709+ , node = node
710+ , children = children
711+ , has = has
712+ }
713+
714+ attribute :: remaining ->
715+ case attribute of
716+ NoAttribute ->
717+ gatherAttrRecursive classes node has transform styles attrs children remaining
718+
719+ Class flag exactClassName ->
720+ if Flag.present flag has then
721+ gatherAttrRecursive classes node has transform styles attrs children remaining
722+ else
723+ gatherAttrRecursive (exactClassName ++ " " ++ classes) node (Flag.add flag has) transform styles attrs children remaining
724+
725+ Attr actualAttribute ->
726+ gatherAttrRecursive classes node has transform styles (actualAttribute :: attrs) children remaining
727+
728+ StyleClass flag style ->
729+ if Flag.present flag has then
730+ gatherAttrRecursive classes node has transform styles attrs children remaining
731+ else if skippable flag style then
732+ gatherAttrRecursive (getStyleName style ++ " " ++ classes)
733+ node
734+ (Flag.add flag has)
735+ transform
736+ styles
737+ attrs
738+ children
739+ remaining
740+ else
741+ gatherAttrRecursive (getStyleName style ++ " " ++ classes)
742+ node
743+ (Flag.add flag has)
744+ transform
745+ (style :: styles)
746+ attrs
747+ children
748+ remaining
749+
750+ TransformComponent flag component ->
751+ gatherAttrRecursive classes
752+ node
753+ (Flag.add flag has)
754+ (composeTransformation transform component)
755+ styles
756+ attrs
757+ children
758+ remaining
759+
760+ Width width ->
761+ if Flag.present Flag.width has then
762+ gatherAttrRecursive classes node has transform styles attrs children remaining
763+ else
764+ case width of
765+ Px px ->
766+ gatherAttrRecursive ((Internal.Style.classes.widthExact ++ " width-px-" ++ String.fromInt px) ++ " " ++ classes)
767+ node
768+ (Flag.add Flag.width has)
769+ transform
770+ (Single ("width-px-" ++ String.fromInt px) "width" (String.fromInt px ++ "px") :: styles)
771+ attrs
772+ children
773+ remaining
774+
775+ Content ->
776+ gatherAttrRecursive (classes ++ " " ++ Internal.Style.classes.widthContent)
777+ node
778+ (Flag.add Flag.widthContent (Flag.add Flag.width has))
779+ transform
780+ styles
781+ attrs
782+ children
783+ remaining
784+
785+ Fill portion ->
786+ if portion == 1 then
787+ gatherAttrRecursive (classes ++ " " ++ Internal.Style.classes.widthFill)
788+ node
789+ (Flag.add Flag.widthFill (Flag.add Flag.width has))
790+ transform
791+ styles
792+ attrs
793+ children
794+ remaining
795+ else
796+ gatherAttrRecursive (classes ++ " " ++ Internal.Style.classes.widthFillPortion ++ " width-fill-" ++ String.fromInt portion)
797+ node
798+ (Flag.add Flag.widthFill (Flag.add Flag.width has))
799+ transform
800+ (Single
801+ (Internal.Style.classes.any
802+ ++ "."
803+ ++ Internal.Style.classes.row
804+ ++ " > "
805+ ++ (Internal.Style.dot <| "width-fill-" ++ String.fromInt portion)
806+ )
807+ "flex-grow"
808+ (String.fromInt (portion * 100000))
809+ :: styles
810+ )
811+ attrs
812+ children
813+ remaining
814+
815+ _ ->
816+ let
817+ ( addToFlags, newClass, newStyles ) =
818+ renderWidth width
819+ in
820+ gatherAttrRecursive (classes ++ " " ++ newClass)
821+ node
822+ (Flag.merge addToFlags has)
823+ transform
824+ (newStyles ++ styles)
825+ attrs
826+ children
827+ remaining
828+
829+ Height height ->
830+ if Flag.present Flag.height has then
831+ gatherAttrRecursive classes node has transform styles attrs children remaining
832+ else
833+ case height of
834+ Px px ->
835+ let
836+ val =
837+ String.fromInt px ++ "px"
838+
839+ name =
840+ "height-px-" ++ val
841+ in
842+ gatherAttrRecursive (name ++ " " ++ classes)
843+ node
844+ (Flag.add Flag.height has)
845+ transform
846+ (Single name "height " val :: styles)
847+ attrs
848+ children
849+ remaining
850+
851+ Content ->
852+ gatherAttrRecursive (Internal.Style.classes.heightContent ++ " " ++ classes)
853+ node
854+ (Flag.add Flag.heightContent (Flag.add Flag.height has))
855+ transform
856+ styles
857+ attrs
858+ children
859+ remaining
860+
861+ Fill portion ->
862+ if portion == 1 then
863+ gatherAttrRecursive (Internal.Style.classes.heightFill ++ " " ++ classes)
864+ node
865+ (Flag.add Flag.heightFill (Flag.add Flag.height has))
866+ transform
867+ styles
868+ attrs
869+ children
870+ remaining
871+ else
872+ gatherAttrRecursive (classes ++ " " ++ (Internal.Style.classes.heightFillPortion ++ " height-fill-" ++ String.fromInt portion))
873+ node
874+ (Flag.add Flag.heightFill (Flag.add Flag.height has))
875+ transform
876+ (Single
877+ (Internal.Style.classes.any
878+ ++ "."
879+ ++ Internal.Style.classes.column
880+ ++ " > "
881+ ++ (Internal.Style.dot <| "height-fill-" ++ String.fromInt portion)
882+ )
883+ "flex-grow"
884+ (String.fromInt (portion * 100000))
885+ :: styles
886+ )
887+ attrs
888+ children
889+ remaining
890+
891+ _ ->
892+ let
893+ ( addToFlags, newClass, newStyles ) =
894+ renderHeight height
895+ in
896+ gatherAttrRecursive (classes ++ " " ++ newClass)
897+ node
898+ (Flag.merge addToFlags has)
899+ transform
900+ (newStyles ++ styles)
901+ attrs
902+ children
903+ remaining
904+
905+ Describe description ->
906+ case description of
907+ Main ->
908+ gatherAttrRecursive classes (addNodeName "main" node) has transform styles attrs children remaining
909+
910+ Navigation ->
911+ gatherAttrRecursive classes (addNodeName "nav" node) has transform styles attrs children remaining
912+
913+ ContentInfo ->
914+ gatherAttrRecursive classes (addNodeName "footer" node) has transform styles attrs children remaining
915+
916+ Complementary ->
917+ gatherAttrRecursive classes (addNodeName "aside" node) has transform styles attrs children remaining
918+
919+ Heading i ->
920+ if i <= 1 then
921+ gatherAttrRecursive classes (addNodeName "h1" node) has transform styles attrs children remaining
922+ else if i < 7 then
923+ gatherAttrRecursive classes (addNodeName ("h" ++ String.fromInt i) node) has transform styles attrs children remaining
924+ else
925+ gatherAttrRecursive classes (addNodeName "h6" node) has transform styles attrs children remaining
926+
927+ Paragraph ->
928+ let
929+ newNode =
930+ case node of
931+ Generic ->
932+ NodeName "p"
933+
934+ NodeName name ->
935+ NodeName name
936+
937+ Embedded x y ->
938+ Embedded x y
939+ in
940+ gatherAttrRecursive classes
941+ newNode
942+ has
943+ transform
944+ styles
945+ attrs
946+ children
947+ remaining
948+
949+ Button ->
950+ gatherAttrRecursive classes node has transform styles (VirtualDom.attribute "role" "button" :: attrs) children remaining
951+
952+ Label label ->
953+ gatherAttrRecursive classes node has transform styles (VirtualDom.attribute "aria-label" label :: attrs) children remaining
954+
955+ LivePolite ->
956+ gatherAttrRecursive classes node has transform styles (VirtualDom.attribute "aria-live" "polite" :: attrs) children remaining
957+
958+ LiveAssertive ->
959+ gatherAttrRecursive classes node has transform styles (VirtualDom.attribute "aria-live" "assertive" :: attrs) children remaining
960+
961+ Nearby location elem ->
962+ let
963+ newStyles =
964+ case elem of
965+ Empty ->
966+ styles
967+
968+ Text str ->
969+ styles
970+
971+ Unstyled html ->
972+ styles
973+
974+ Styled styled ->
975+ styles ++ styled.styles
976+
977+ nearbyElement =
978+ Html.div
979+ [ Html.Attributes.class <|
980+ case location of
981+ Above ->
982+ String.join " "
983+ [ Internal.Style.classes.any
984+ , Internal.Style.classes.single
985+ , Internal.Style.classes.above
986+ ]
987+
988+ Below ->
989+ String.join " "
990+ [ Internal.Style.classes.any
991+ , Internal.Style.classes.single
992+ , Internal.Style.classes.below
993+ ]
994+
995+ OnRight ->
996+ String.join " "
997+ [ Internal.Style.classes.any
998+ , Internal.Style.classes.single
999+ , Internal.Style.classes.onRight
1000+ ]
1001+
1002+ OnLeft ->
1003+ String.join " "
1004+ [ Internal.Style.classes.any
1005+ , Internal.Style.classes.single
1006+ , Internal.Style.classes.onLeft
1007+ ]
1008+
1009+ InFront ->
1010+ String.join " "
1011+ [ Internal.Style.classes.any
1012+ , Internal.Style.classes.single
1013+ , Internal.Style.classes.inFront
1014+ ]
1015+
1016+ Behind ->
1017+ String.join " "
1018+ [ Internal.Style.classes.any
1019+ , Internal.Style.classes.single
1020+ , Internal.Style.classes.behind
1021+ ]
1022+ ]
1023+ [ case elem of
1024+ Empty ->
1025+ VirtualDom.text ""
1026+
1027+ Text str ->
1028+ textElement str
1029+
1030+ Unstyled html ->
1031+ html asEl
1032+
1033+ Styled styled ->
1034+ styled.html NoStyleSheet asEl
1035+ ]
1036+
1037+ newClasses =
1038+ if location == Behind then
1039+ Internal.Style.classes.hasBehind ++ " " ++ classes
1040+ else
1041+ classes
1042+ in
1043+ gatherAttrRecursive newClasses node has transform newStyles attrs (nearbyElement :: children) remaining
1044+
1045+ AlignX x ->
1046+ if Flag.present Flag.xAlign has then
1047+ gatherAttrRecursive classes node has transform styles attrs children remaining
1048+ else
1049+ gatherAttrRecursive (alignXName x ++ " " ++ classes)
1050+ node
1051+ (has
1052+ |> Flag.add Flag.xAlign
1053+ |> (\flags ->
1054+ case x of
1055+ CenterX ->
1056+ Flag.add Flag.centerX flags
1057+
1058+ Right ->
1059+ Flag.add Flag.alignRight flags
1060+
1061+ _ ->
1062+ flags
1063+ )
1064+ )
1065+ transform
1066+ styles
1067+ attrs
1068+ children
1069+ remaining
1070+
1071+ AlignY y ->
1072+ if Flag.present Flag.yAlign has then
1073+ gatherAttrRecursive classes node has transform styles attrs children remaining
1074+ else
1075+ gatherAttrRecursive (alignYName y ++ " " ++ classes)
1076+ node
1077+ (Flag.add Flag.yAlign has
1078+ |> (\flags ->
1079+ case y of
1080+ CenterY ->
1081+ Flag.add Flag.centerY flags
1082+
1083+ Bottom ->
1084+ Flag.add Flag.alignBottom flags
1085+
1086+ _ ->
1087+ flags
1088+ )
1089+ )
1090+ transform
1091+ styles
1092+ attrs
1093+ children
1094+ remaining
1095+
1096+
1097+renderWidth w =
1098+ case w of
1099+ Px px ->
1100+ ( Flag.none
1101+ , Internal.Style.classes.widthExact ++ " width-px-" ++ String.fromInt px
1102+ , [ Single ("width-px-" ++ String.fromInt px) "width" (String.fromInt px ++ "px") ]
1103+ )
1104+
1105+ Content ->
1106+ ( Flag.add Flag.widthContent Flag.none
1107+ , Internal.Style.classes.widthContent
1108+ , []
1109+ )
1110+
1111+ Fill portion ->
1112+ if portion == 1 then
1113+ ( Flag.add Flag.widthFill Flag.none
1114+ , Internal.Style.classes.widthFill
1115+ , []
1116+ )
1117+ else
1118+ ( Flag.add Flag.widthFill Flag.none
1119+ , Internal.Style.classes.widthFillPortion ++ " width-fill-" ++ String.fromInt portion
1120+ , [ Single
1121+ (Internal.Style.classes.any
1122+ ++ "."
1123+ ++ Internal.Style.classes.row
1124+ ++ " > "
1125+ ++ (Internal.Style.dot <| "width-fill-" ++ String.fromInt portion)
1126+ )
1127+ "flex-grow"
1128+ (String.fromInt (portion * 100000))
1129+ ]
1130+ )
1131+
1132+ Min minSize len ->
1133+ let
1134+ cls =
1135+ "min-width-"
1136+ ++ String.fromInt minSize
1137+
1138+ style =
1139+ Single
1140+ cls
1141+ "min-width"
1142+ (String.fromInt minSize ++ "px")
1143+
1144+ ( newFlag, newAttrs, newStyle ) =
1145+ renderWidth len
1146+ in
1147+ ( Flag.add Flag.widthBetween newFlag
1148+ , cls ++ " " ++ newAttrs
1149+ , style :: newStyle
1150+ )
1151+
1152+ Max maxSize len ->
1153+ let
1154+ cls =
1155+ "max-width-" ++ String.fromInt maxSize
1156+
1157+ style =
1158+ Single cls
1159+ "max-width"
1160+ (String.fromInt maxSize ++ "px")
1161+
1162+ ( newFlag, newAttrs, newStyle ) =
1163+ renderWidth len
1164+ in
1165+ ( Flag.add Flag.widthBetween newFlag
1166+ , cls ++ " " ++ newAttrs
1167+ , style :: newStyle
1168+ )
1169+
1170+
1171+renderHeight h =
1172+ case h of
1173+ Px px ->
1174+ let
1175+ val =
1176+ String.fromInt px
1177+
1178+ name =
1179+ "height-px-" ++ val
1180+ in
1181+ ( Flag.none
1182+ , name
1183+ , [ Single name "height" (val ++ "px") ]
1184+ )
1185+
1186+ Content ->
1187+ ( Flag.add Flag.heightContent Flag.none
1188+ , Internal.Style.classes.heightContent
1189+ , []
1190+ )
1191+
1192+ Fill portion ->
1193+ if portion == 1 then
1194+ ( Flag.add Flag.heightFill Flag.none
1195+ , Internal.Style.classes.heightFill
1196+ , []
1197+ )
1198+ else
1199+ ( Flag.add Flag.heightFill Flag.none
1200+ , Internal.Style.classes.heightFillPortion ++ " height-fill-" ++ String.fromInt portion
1201+ , [ Single
1202+ (Internal.Style.classes.any
1203+ ++ "."
1204+ ++ Internal.Style.classes.row
1205+ ++ " > "
1206+ ++ (Internal.Style.dot <| "height-fill-" ++ String.fromInt portion)
1207+ )
1208+ "flex-grow"
1209+ (String.fromInt (portion * 100000))
1210+ ]
1211+ )
1212+
1213+ Min minSize len ->
1214+ let
1215+ cls =
1216+ "min-height-"
1217+ ++ String.fromInt minSize
1218+
1219+ style =
1220+ Single
1221+ cls
1222+ "min-height"
1223+ (String.fromInt minSize ++ "px")
1224+
1225+ ( newFlag, newAttrs, newStyle ) =
1226+ renderHeight len
1227+ in
1228+ ( Flag.add Flag.heightBetween newFlag
1229+ , cls ++ " " ++ newAttrs
1230+ , style :: newStyle
1231+ )
1232+
1233+ Max maxSize len ->
1234+ let
1235+ cls =
1236+ "max-height-" ++ String.fromInt maxSize
1237+
1238+ style =
1239+ Single cls
1240+ "max-height"
1241+ (String.fromInt maxSize ++ "px")
1242+
1243+ ( newFlag, newAttrs, newStyle ) =
1244+ renderHeight len
1245+ in
1246+ ( Flag.add Flag.heightBetween newFlag
1247+ , cls ++ " " ++ newAttrs
1248+ , style :: newStyle
1249+ )
1250+
1251+
1252+rowClass =
1253+ classes.any ++ " " ++ classes.row
1254+
1255+
1256+columnClass =
1257+ classes.any ++ " " ++ classes.column
1258+
1259+
1260+singleClass =
1261+ classes.any ++ " " ++ classes.single
1262+
1263+
1264+gridClass =
1265+ classes.any ++ " " ++ classes.grid
1266+
1267+
1268+paragraphClass =
1269+ classes.any ++ " " ++ classes.paragraph
1270+
1271+
1272+pageClass =
1273+ classes.any ++ " " ++ classes.page
1274+
1275+
1276+contextClasses context =
1277+ case context of
1278+ AsRow ->
1279+ rowClass
1280+
1281+ AsColumn ->
1282+ columnClass
1283+
1284+ AsEl ->
1285+ singleClass
1286+
1287+ AsGrid ->
1288+ gridClass
1289+
1290+ AsParagraph ->
1291+ paragraphClass
1292+
1293+ AsTextColumn ->
1294+ pageClass
1295+
1296+
1297+element : LayoutContext -> NodeName -> List (Attribute aligned msg) -> Children (Element msg) -> Element msg
1298+element context node attributes children =
1299+ attributes
1300+ |> List.reverse
1301+ |> gatherAttrRecursive (contextClasses context) node Flag.none untransformed [] [] []
1302+ |> createElement context children
1303+
1304+
1305+untransformed =
1306+ Untransformed
1307+
1308+
1309+
1310+-- space =
1311+-- VirtualDom.text " "
1312+-- keyedSpace =
1313+-- ( " ", space )
1314+
1315+
1316+createElement : LayoutContext -> Children (Element msg) -> Gathered msg -> Element msg
1317+createElement context children rendered =
1318+ let
1319+ gather child ( htmls, existingStyles ) =
1320+ case child of
1321+ Unstyled html ->
1322+ if context == asParagraph then
1323+ ( html context :: htmls
1324+ , existingStyles
1325+ )
1326+ else
1327+ ( html context :: htmls
1328+ , existingStyles
1329+ )
1330+
1331+ Styled styled ->
1332+ if context == asParagraph then
1333+ ( styled.html NoStyleSheet context :: htmls
1334+ , if List.isEmpty existingStyles then
1335+ styled.styles
1336+ else
1337+ styled.styles ++ existingStyles
1338+ )
1339+ else
1340+ ( styled.html NoStyleSheet context :: htmls
1341+ , if List.isEmpty existingStyles then
1342+ styled.styles
1343+ else
1344+ styled.styles ++ existingStyles
1345+ )
1346+
1347+ Text str ->
1348+ -- TEXT OPTIMIZATION
1349+ -- You can have raw text if the element is an el, and has `width-content` and `height-content`
1350+ -- Same if it's a column or row with one child and width-content, height-content
1351+ -- interferes with css grid
1352+ -- Maybe we could unpack text elements in a paragraph as well,
1353+ -- however embedded style elements that are larger than the line height will overlap with exisitng text.
1354+ -- I don't think that's what we want.
1355+ if
1356+ context
1357+ == asEl
1358+ || context
1359+ == asParagraph
1360+ then
1361+ ( VirtualDom.text
1362+ (if context == asParagraph then
1363+ str ++ " "
1364+ else
1365+ str
1366+ )
1367+ :: htmls
1368+ , existingStyles
1369+ )
1370+ else
1371+ ( textElement
1372+ (if context == asParagraph then
1373+ str ++ " "
1374+ else
1375+ str
1376+ )
1377+ :: htmls
1378+ , existingStyles
1379+ )
1380+
1381+ Empty ->
1382+ ( htmls, existingStyles )
1383+
1384+ gatherKeyed ( key, child ) ( htmls, existingStyles ) =
1385+ case child of
1386+ Unstyled html ->
1387+ if context == asParagraph then
1388+ ( ( key, html context ) :: htmls
1389+ , existingStyles
1390+ )
1391+ else
1392+ ( ( key, html context ) :: htmls
1393+ , existingStyles
1394+ )
1395+
1396+ Styled styled ->
1397+ if context == asParagraph then
1398+ ( ( key, styled.html NoStyleSheet context )
1399+ :: htmls
1400+ , if List.isEmpty existingStyles then
1401+ styled.styles
1402+ else
1403+ styled.styles ++ existingStyles
1404+ )
1405+ else
1406+ ( ( key, styled.html NoStyleSheet context ) :: htmls
1407+ , if List.isEmpty existingStyles then
1408+ styled.styles
1409+ else
1410+ styled.styles ++ existingStyles
1411+ )
1412+
1413+ Text str ->
1414+ -- TEXT OPTIMIZATION
1415+ -- You can have raw text if the element is an el, and has `width-content` and `height-content`
1416+ -- Same if it's a column or row with one child and width-content, height-content
1417+ if
1418+ context
1419+ == asEl
1420+ || context
1421+ == asParagraph
1422+ then
1423+ ( ( key
1424+ , VirtualDom.text
1425+ (if context == asParagraph then
1426+ str ++ " "
1427+ else
1428+ str
1429+ )
1430+ )
1431+ :: htmls
1432+ , existingStyles
1433+ )
1434+ else
1435+ ( ( key
1436+ , textElement
1437+ (if context == asParagraph then
1438+ str ++ " "
1439+ else
1440+ str
1441+ )
1442+ )
1443+ :: htmls
1444+ , existingStyles
1445+ )
1446+
1447+ Empty ->
1448+ ( htmls, existingStyles )
1449+ in
1450+ case children of
1451+ Keyed keyedChildren ->
1452+ case List.foldr gatherKeyed ( [], [] ) keyedChildren of
1453+ ( keyed, styles ) ->
1454+ let
1455+ newStyles =
1456+ if List.isEmpty styles then
1457+ rendered.styles
1458+ else
1459+ rendered.styles ++ styles
1460+ in
1461+ case newStyles of
1462+ [] ->
1463+ Unstyled
1464+ (finalizeNode rendered.has
1465+ rendered.node
1466+ rendered.attributes
1467+ (Keyed <| List.map (\x -> ( "nearby-elements-pls", x )) rendered.children ++ keyed)
1468+ NoStyleSheet
1469+ )
1470+
1471+ allStyles ->
1472+ Styled
1473+ { styles = allStyles
1474+ , html =
1475+ finalizeNode rendered.has rendered.node rendered.attributes (Keyed (List.map (\x -> ( "nearby-elements-pls", x )) rendered.children ++ keyed))
1476+ }
1477+
1478+ Unkeyed unkeyedChildren ->
1479+ case List.foldr gather ( [], [] ) unkeyedChildren of
1480+ ( unkeyed, styles ) ->
1481+ let
1482+ newStyles =
1483+ if List.isEmpty styles then
1484+ rendered.styles
1485+ else
1486+ rendered.styles ++ styles
1487+ in
1488+ case newStyles of
1489+ [] ->
1490+ Unstyled
1491+ (finalizeNode rendered.has
1492+ rendered.node
1493+ rendered.attributes
1494+ (Unkeyed <| rendered.children ++ unkeyed)
1495+ NoStyleSheet
1496+ )
1497+
1498+ allStyles ->
1499+ Styled
1500+ { styles = allStyles
1501+ , html = finalizeNode rendered.has rendered.node rendered.attributes (Unkeyed (rendered.children ++ unkeyed))
1502+ }
1503+
1504+
1505+unit =
1506+ 0
1507+
1508+
1509+defaultOptions =
1510+ { hover = AllowHover
1511+ , focus = focusDefaultStyle
1512+ , mode = Layout
1513+ }
1514+
1515+
1516+staticRoot =
1517+ VirtualDom.node "style" [] [ VirtualDom.text Internal.Style.rules ]
1518+
1519+
1520+addWhen ifThis x to =
1521+ if ifThis then
1522+ x :: to
1523+ else
1524+ to
1525+
1526+
1527+{-| TODO:
1528+
1529+This doesn't reduce equivalent attributes completely.
1530+
1531+-}
1532+filter : List (Attribute aligned msg) -> List (Attribute aligned msg)
1533+filter attrs =
1534+ Tuple.first <|
1535+ List.foldr
1536+ (\x ( found, has ) ->
1537+ case x of
1538+ NoAttribute ->
1539+ ( found, has )
1540+
1541+ Class key _ ->
1542+ ( x :: found, has )
1543+
1544+ Attr attr ->
1545+ ( x :: found, has )
1546+
1547+ StyleClass _ style ->
1548+ ( x :: found, has )
1549+
1550+ Width width ->
1551+ if Set.member "width" has then
1552+ ( found, has )
1553+ else
1554+ ( x :: found, Set.insert "width" has )
1555+
1556+ Height height ->
1557+ if Set.member "height" has then
1558+ ( found, has )
1559+ else
1560+ ( x :: found, Set.insert "height" has )
1561+
1562+ Describe description ->
1563+ if Set.member "described" has then
1564+ ( found, has )
1565+ else
1566+ ( x :: found, Set.insert "described" has )
1567+
1568+ Nearby location elem ->
1569+ ( x :: found, has )
1570+
1571+ AlignX _ ->
1572+ if Set.member "align-x" has then
1573+ ( found, has )
1574+ else
1575+ ( x :: found, Set.insert "align-x" has )
1576+
1577+ AlignY _ ->
1578+ if Set.member "align-y" has then
1579+ ( found, has )
1580+ else
1581+ ( x :: found, Set.insert "align-y" has )
1582+
1583+ TransformComponent _ _ ->
1584+ if Set.member "transform" has then
1585+ ( found, has )
1586+ else
1587+ ( x :: found, Set.insert "transform" has )
1588+ )
1589+ ( [], Set.empty )
1590+ attrs
1591+
1592+
1593+get : List (Attribute aligned msg) -> (Attribute aligned msg -> Bool) -> List (Attribute aligned msg)
1594+get attrs isAttr =
1595+ attrs
1596+ |> filter
1597+ |> List.foldr
1598+ (\x found ->
1599+ if isAttr x then
1600+ x :: found
1601+ else
1602+ found
1603+ )
1604+ []
1605+
1606+
1607+type Spacing
1608+ = Spaced String Int Int
1609+
1610+
1611+type Padding
1612+ = Padding String Int Int Int Int
1613+
1614+
1615+extractSpacingAndPadding : List (Attribute aligned msg) -> ( Maybe Padding, Maybe Spacing )
1616+extractSpacingAndPadding attrs =
1617+ List.foldr
1618+ (\attr ( pad, spacing ) ->
1619+ ( case pad of
1620+ Just x ->
1621+ pad
1622+
1623+ Nothing ->
1624+ case attr of
1625+ StyleClass _ (PaddingStyle name t r b l) ->
1626+ Just (Padding name t r b l)
1627+
1628+ _ ->
1629+ Nothing
1630+ , case spacing of
1631+ Just x ->
1632+ spacing
1633+
1634+ Nothing ->
1635+ case attr of
1636+ StyleClass _ (SpacingStyle name x y) ->
1637+ Just (Spaced name x y)
1638+
1639+ _ ->
1640+ Nothing
1641+ )
1642+ )
1643+ ( Nothing, Nothing )
1644+ attrs
1645+
1646+
1647+getSpacing : List (Attribute aligned msg) -> ( Int, Int ) -> ( Int, Int )
1648+getSpacing attrs default =
1649+ attrs
1650+ |> List.foldr
1651+ (\attr acc ->
1652+ case acc of
1653+ Just x ->
1654+ Just x
1655+
1656+ Nothing ->
1657+ case attr of
1658+ StyleClass _ (SpacingStyle _ x y) ->
1659+ Just ( x, y )
1660+
1661+ _ ->
1662+ Nothing
1663+ )
1664+ Nothing
1665+ |> Maybe.withDefault default
1666+
1667+
1668+getWidth : List (Attribute aligned msg) -> Maybe Length
1669+getWidth attrs =
1670+ attrs
1671+ |> List.foldr
1672+ (\attr acc ->
1673+ case acc of
1674+ Just x ->
1675+ Just x
1676+
1677+ Nothing ->
1678+ case attr of
1679+ Width len ->
1680+ Just len
1681+
1682+ _ ->
1683+ Nothing
1684+ )
1685+ Nothing
1686+
1687+
1688+getHeight : List (Attribute aligned msg) -> Maybe Length
1689+getHeight attrs =
1690+ attrs
1691+ |> List.foldr
1692+ (\attr acc ->
1693+ case acc of
1694+ Just x ->
1695+ Just x
1696+
1697+ Nothing ->
1698+ case attr of
1699+ Height len ->
1700+ Just len
1701+
1702+ _ ->
1703+ Nothing
1704+ )
1705+ Nothing
1706+
1707+
1708+textElement : String -> VirtualDom.Node msg
1709+textElement str =
1710+ Html.div
1711+ [ Html.Attributes.class
1712+ (String.join " "
1713+ [ classes.any
1714+ , classes.text
1715+ , classes.widthContent
1716+ , classes.heightContent
1717+ ]
1718+ )
1719+ ]
1720+ [ Html.text str ]
1721+
1722+
1723+textElementFill : String -> VirtualDom.Node msg
1724+textElementFill str =
1725+ VirtualDom.node "div"
1726+ [ VirtualDom.property "className"
1727+ (Json.string <|
1728+ String.join " "
1729+ [ classes.any
1730+ , classes.text
1731+ , classes.widthFill
1732+ , classes.heightFill
1733+ ]
1734+ )
1735+ ]
1736+ [ VirtualDom.text str ]
1737+
1738+
1739+type Children x
1740+ = Unkeyed (List x)
1741+ | Keyed (List ( String, x ))
1742+
1743+
1744+
1745+-- toHtml : OptionRecord -> Element msg -> VirtualDom.Node msg
1746+
1747+
1748+toHtml mode el =
1749+ case el of
1750+ Unstyled html ->
1751+ html asEl
1752+
1753+ Styled { styles, html } ->
1754+ html (mode styles) asEl
1755+
1756+ Text text ->
1757+ textElement text
1758+
1759+ Empty ->
1760+ textElement ""
1761+
1762+
1763+{-| -}
1764+renderRoot : List Option -> List (Attribute aligned msg) -> Element msg -> VirtualDom.Node msg
1765+renderRoot optionList attributes child =
1766+ let
1767+ options =
1768+ optionsToRecord optionList
1769+
1770+ embedStyle =
1771+ case options.mode of
1772+ NoStaticStyleSheet ->
1773+ OnlyDynamic options
1774+
1775+ _ ->
1776+ StaticRootAndDynamic options
1777+ in
1778+ element asEl div attributes (Unkeyed [ child ])
1779+ |> toHtml embedStyle
1780+
1781+
1782+type RenderMode
1783+ = Viewport
1784+ | Layout
1785+ | NoStaticStyleSheet
1786+ | WithVirtualCss
1787+
1788+
1789+type alias OptionRecord =
1790+ { hover : HoverSetting
1791+ , focus : FocusStyle
1792+ , mode : RenderMode
1793+ }
1794+
1795+
1796+type HoverSetting
1797+ = NoHover
1798+ | AllowHover
1799+ | ForceHover
1800+
1801+
1802+type Option
1803+ = HoverOption HoverSetting
1804+ | FocusStyleOption FocusStyle
1805+ | RenderModeOption RenderMode
1806+
1807+
1808+type alias FocusStyle =
1809+ { borderColor : Maybe Color
1810+ , shadow : Maybe Shadow
1811+ , backgroundColor : Maybe Color
1812+ }
1813+
1814+
1815+type alias Shadow =
1816+ { color : Color
1817+ , offset : ( Int, Int )
1818+ , blur : Int
1819+ , size : Int
1820+ }
1821+
1822+
1823+rootStyle : List (Attribute aligned msg)
1824+rootStyle =
1825+ let
1826+ families =
1827+ [ Typeface "Open Sans"
1828+ , Typeface "Helvetica"
1829+ , Typeface "Verdana"
1830+ , SansSerif
1831+ ]
1832+ in
1833+ [ StyleClass Flag.bgColor (Colored ("bg-color-" ++ formatColorClass (Rgba 1 1 1 1)) "background-color" (Rgba 1 1 1 1))
1834+ , StyleClass Flag.fontColor (Colored ("font-color-" ++ formatColorClass (Rgba 0 0 0 1)) "color" (Rgba 0 0 0 1))
1835+
1836+ -- , StyleClass Flag.fontSize (Single "font-size-20" "font-size" "20px")
1837+ , StyleClass Flag.fontSize (FontSize 20)
1838+ , StyleClass Flag.fontFamily <|
1839+ FontFamily (List.foldl renderFontClassName "font-" families)
1840+ families
1841+ ]
1842+
1843+
1844+renderFontClassName : Font -> String -> String
1845+renderFontClassName font current =
1846+ current
1847+ ++ (case font of
1848+ Serif ->
1849+ "serif"
1850+
1851+ SansSerif ->
1852+ "sans-serif"
1853+
1854+ Monospace ->
1855+ "monospace"
1856+
1857+ Typeface name ->
1858+ name
1859+ |> String.toLower
1860+ |> String.words
1861+ |> String.join "-"
1862+
1863+ ImportFont name url ->
1864+ name
1865+ |> String.toLower
1866+ |> String.words
1867+ |> String.join "-"
1868+ )
1869+
1870+
1871+renderFocusStyle :
1872+ FocusStyle
1873+ -> Style
1874+renderFocusStyle focus =
1875+ Style (Internal.Style.dot classes.any ++ ":focus .focusable, " ++ Internal.Style.dot classes.any ++ ".focusable:focus")
1876+ (List.filterMap identity
1877+ [ Maybe.map (\color -> Property "border-color" (formatColor color)) focus.borderColor
1878+ , Maybe.map (\color -> Property "background-color" (formatColor color)) focus.backgroundColor
1879+ , Maybe.map
1880+ (\shadow ->
1881+ Property "box-shadow"
1882+ (formatBoxShadow
1883+ { color = shadow.color
1884+ , offset =
1885+ shadow.offset
1886+ |> Tuple.mapFirst toFloat
1887+ |> Tuple.mapSecond toFloat
1888+ , inset = False
1889+ , blur = toFloat shadow.blur
1890+ , size = toFloat shadow.size
1891+ }
1892+ )
1893+ )
1894+ focus.shadow
1895+ , Just <| Property "outline" "none"
1896+ ]
1897+ )
1898+
1899+
1900+focusDefaultStyle : { backgroundColor : Maybe Color, borderColor : Maybe Color, shadow : Maybe Shadow }
1901+focusDefaultStyle =
1902+ { backgroundColor = Nothing
1903+ , borderColor = Nothing
1904+ , shadow =
1905+ Just
1906+ { color =
1907+ Rgba (155 / 255) (203 / 255) 1 1
1908+ , offset = ( 0, 0 )
1909+ , blur = 3
1910+ , size = 3
1911+ }
1912+ }
1913+
1914+
1915+optionsToRecord : List Option -> OptionRecord
1916+optionsToRecord options =
1917+ let
1918+ combine opt record =
1919+ case opt of
1920+ HoverOption hoverable ->
1921+ case record.hover of
1922+ Nothing ->
1923+ { record | hover = Just hoverable }
1924+
1925+ _ ->
1926+ record
1927+
1928+ FocusStyleOption focusStyle ->
1929+ case record.focus of
1930+ Nothing ->
1931+ { record | focus = Just focusStyle }
1932+
1933+ _ ->
1934+ record
1935+
1936+ RenderModeOption renderMode ->
1937+ case record.mode of
1938+ Nothing ->
1939+ { record | mode = Just renderMode }
1940+
1941+ _ ->
1942+ record
1943+
1944+ andFinally record =
1945+ { hover =
1946+ case record.hover of
1947+ Nothing ->
1948+ AllowHover
1949+
1950+ Just hoverable ->
1951+ hoverable
1952+ , focus =
1953+ case record.focus of
1954+ Nothing ->
1955+ focusDefaultStyle
1956+
1957+ Just focusable ->
1958+ focusable
1959+ , mode =
1960+ case record.mode of
1961+ Nothing ->
1962+ Layout
1963+
1964+ Just actualMode ->
1965+ actualMode
1966+ }
1967+ in
1968+ andFinally <|
1969+ List.foldr combine
1970+ { hover = Nothing
1971+ , focus = Nothing
1972+ , mode = Nothing
1973+ }
1974+ options
1975+
1976+
1977+renderFont : List Font -> String
1978+renderFont families =
1979+ let
1980+ fontName font =
1981+ case font of
1982+ Serif ->
1983+ "serif"
1984+
1985+ SansSerif ->
1986+ "sans-serif"
1987+
1988+ Monospace ->
1989+ "monospace"
1990+
1991+ Typeface name ->
1992+ "\"" ++ name ++ "\""
1993+
1994+ ImportFont name url ->
1995+ "\"" ++ name ++ "\""
1996+ in
1997+ families
1998+ |> List.map fontName
1999+ |> String.join ", "
2000+
2001+
2002+toStyleSheet : OptionRecord -> List Style -> VirtualDom.Node msg
2003+toStyleSheet options styleSheet =
2004+ VirtualDom.node "style" [] [ VirtualDom.text (toStyleSheetString options styleSheet) ]
2005+
2006+
2007+toStyleSheetString : OptionRecord -> List Style -> String
2008+toStyleSheetString options stylesheet =
2009+ let
2010+ renderTopLevels rule =
2011+ case rule of
2012+ FontFamily name typefaces ->
2013+ let
2014+ getImports font =
2015+ case font of
2016+ ImportFont _ url ->
2017+ Just ("@import url('" ++ url ++ "');")
2018+
2019+ _ ->
2020+ Nothing
2021+ in
2022+ typefaces
2023+ |> List.filterMap getImports
2024+ |> String.join "\n"
2025+ |> Just
2026+
2027+ _ ->
2028+ Nothing
2029+
2030+ renderProps force (Property key val) existing =
2031+ if force then
2032+ existing ++ "\n " ++ key ++ ": " ++ val ++ " !important;"
2033+ else
2034+ existing ++ "\n " ++ key ++ ": " ++ val ++ ";"
2035+
2036+ renderStyle maybePseudo selector props =
2037+ case maybePseudo of
2038+ Nothing ->
2039+ selector ++ "{" ++ List.foldl (renderProps False) "" props ++ "\n}"
2040+
2041+ Just pseudo ->
2042+ case pseudo of
2043+ Hover ->
2044+ case options.hover of
2045+ NoHover ->
2046+ ""
2047+
2048+ ForceHover ->
2049+ selector ++ "-hv {" ++ List.foldl (renderProps True) "" props ++ "\n}"
2050+
2051+ AllowHover ->
2052+ selector ++ "-hv:hover {" ++ List.foldl (renderProps False) "" props ++ "\n}"
2053+
2054+ Focus ->
2055+ let
2056+ renderedProps =
2057+ List.foldl (renderProps False) "" props
2058+ in
2059+ String.join "\n"
2060+ [ selector
2061+ ++ "-fs:focus {"
2062+ ++ renderedProps
2063+ ++ "\n}"
2064+ , "."
2065+ ++ classes.any
2066+ ++ ":focus ~ "
2067+ ++ selector
2068+ ++ "-fs:not(.focus) {"
2069+ ++ renderedProps
2070+ ++ "\n}"
2071+ , "."
2072+ ++ classes.any
2073+ ++ ":focus "
2074+ ++ selector
2075+ ++ "-fs {"
2076+ ++ renderedProps
2077+ ++ "\n}"
2078+ , ".focusable-parent:focus ~ "
2079+ ++ "."
2080+ ++ classes.any
2081+ ++ " "
2082+ ++ selector
2083+ ++ "-fs {"
2084+ ++ renderedProps
2085+ ++ "\n}"
2086+ ]
2087+
2088+ Active ->
2089+ selector ++ "-act:active {" ++ List.foldl (renderProps False) "" props ++ "\n}"
2090+
2091+ renderStyleRule rule maybePseudo =
2092+ case rule of
2093+ Style selector props ->
2094+ renderStyle maybePseudo selector props
2095+
2096+ Shadows name prop ->
2097+ renderStyle
2098+ maybePseudo
2099+ ("." ++ name)
2100+ [ Property "box-shadow" prop
2101+ ]
2102+
2103+ Transparency name transparency ->
2104+ let
2105+ opacity =
2106+ (1 - transparency)
2107+ |> min 1
2108+ |> max 0
2109+ in
2110+ renderStyle
2111+ maybePseudo
2112+ ("." ++ name)
2113+ [ Property "opacity" (String.fromFloat opacity)
2114+ ]
2115+
2116+ FontSize i ->
2117+ renderStyle
2118+ maybePseudo
2119+ (".font-size-" ++ String.fromInt i)
2120+ [ Property "font-size" (String.fromInt i ++ "px")
2121+ ]
2122+
2123+ FontFamily name typefaces ->
2124+ renderStyle
2125+ maybePseudo
2126+ ("." ++ name)
2127+ [ Property "font-family" (renderFont typefaces)
2128+ ]
2129+
2130+ Single class prop val ->
2131+ renderStyle
2132+ maybePseudo
2133+ ("." ++ class)
2134+ [ Property prop val
2135+ ]
2136+
2137+ Colored class prop color ->
2138+ renderStyle
2139+ maybePseudo
2140+ ("." ++ class)
2141+ [ Property prop (formatColor color)
2142+ ]
2143+
2144+ SpacingStyle cls x y ->
2145+ let
2146+ class =
2147+ "." ++ cls
2148+
2149+ xPx =
2150+ String.fromInt x ++ "px"
2151+
2152+ yPx =
2153+ String.fromInt y ++ "px"
2154+
2155+ row =
2156+ "." ++ Internal.Style.classes.row
2157+
2158+ wrappedRow =
2159+ "." ++ Internal.Style.classes.wrapped ++ row
2160+
2161+ column =
2162+ "." ++ Internal.Style.classes.column
2163+
2164+ page =
2165+ "." ++ Internal.Style.classes.page
2166+
2167+ paragraph =
2168+ "." ++ Internal.Style.classes.paragraph
2169+
2170+ left =
2171+ "." ++ Internal.Style.classes.alignLeft
2172+
2173+ right =
2174+ "." ++ Internal.Style.classes.alignRight
2175+
2176+ any =
2177+ "." ++ Internal.Style.classes.any
2178+
2179+ single =
2180+ "." ++ Internal.Style.classes.single
2181+ in
2182+ String.concat
2183+ [ renderStyle maybePseudo (class ++ row ++ " > " ++ any) [ Property "margin-right" xPx ]
2184+
2185+ -- margins don't apply to last element of normal, unwrapped rows
2186+ , renderStyle maybePseudo (class ++ row ++ " > " ++ any ++ ":last-child") [ Property "margin" "0" ]
2187+
2188+ -- For wrapped rows, margins always apply because we handle "canceling out" the other margins manually in the element.
2189+ , renderStyle maybePseudo
2190+ (class ++ wrappedRow ++ " > " ++ any)
2191+ [ Property "margin" ("0 " ++ xPx ++ " " ++ yPx ++ " 0")
2192+ ]
2193+ , renderStyle maybePseudo
2194+ (class ++ wrappedRow ++ " > " ++ any ++ ":last-child")
2195+ [ Property "margin-right" "0"
2196+ ]
2197+
2198+ -- columns
2199+ , renderStyle maybePseudo (class ++ column ++ " > " ++ any ++ " + " ++ any) [ Property "margin-top" yPx ]
2200+ , renderStyle maybePseudo (class ++ page ++ " > " ++ any ++ " + " ++ any) [ Property "margin-top" yPx ]
2201+ , renderStyle maybePseudo (class ++ page ++ " > " ++ left) [ Property "margin-right" xPx ]
2202+ , renderStyle maybePseudo (class ++ page ++ " > " ++ right) [ Property "margin-left" xPx ]
2203+ , renderStyle
2204+ maybePseudo
2205+ (class ++ paragraph)
2206+ [ Property "line-height" ("calc(1em + " ++ String.fromInt y ++ "px)")
2207+ ]
2208+ , renderStyle
2209+ maybePseudo
2210+ ("textarea" ++ class)
2211+ [ Property "line-height" ("calc(1em + " ++ String.fromInt y ++ "px)")
2212+ ]
2213+
2214+ -- , renderStyle
2215+ -- maybePseudo
2216+ -- (class ++ paragraph ++ " > " ++ any)
2217+ -- [ Property "margin-right" xPx
2218+ -- , Property "margin-bottom" yPx
2219+ -- ]
2220+ , renderStyle
2221+ maybePseudo
2222+ (class ++ paragraph ++ " > " ++ left)
2223+ [ Property "margin-right" xPx
2224+ ]
2225+ , renderStyle
2226+ maybePseudo
2227+ (class ++ paragraph ++ " > " ++ right)
2228+ [ Property "margin-left" xPx
2229+ ]
2230+ , renderStyle
2231+ maybePseudo
2232+ (class ++ paragraph ++ "::after")
2233+ [ Property "content" "''"
2234+ , Property "display" "block"
2235+ , Property "height" "0"
2236+ , Property "width" "0"
2237+ , Property "margin-top" (String.fromInt (-1 * (y // 2)) ++ "px")
2238+ ]
2239+ , renderStyle
2240+ maybePseudo
2241+ (class ++ paragraph ++ "::before")
2242+ [ Property "content" "''"
2243+ , Property "display" "block"
2244+ , Property "height" "0"
2245+ , Property "width" "0"
2246+ , Property "margin-bottom" (String.fromInt (-1 * (y // 2)) ++ "px")
2247+ ]
2248+ ]
2249+
2250+ PaddingStyle cls top right bottom left ->
2251+ let
2252+ class =
2253+ "."
2254+ ++ cls
2255+ in
2256+ renderStyle
2257+ maybePseudo
2258+ class
2259+ [ Property "padding"
2260+ (String.fromInt top
2261+ ++ "px "
2262+ ++ String.fromInt right
2263+ ++ "px "
2264+ ++ String.fromInt bottom
2265+ ++ "px "
2266+ ++ String.fromInt left
2267+ ++ "px"
2268+ )
2269+ ]
2270+
2271+ GridTemplateStyle template ->
2272+ let
2273+ class =
2274+ ".grid-rows-"
2275+ ++ String.join "-" (List.map lengthClassName template.rows)
2276+ ++ "-cols-"
2277+ ++ String.join "-" (List.map lengthClassName template.columns)
2278+ ++ "-space-x-"
2279+ ++ lengthClassName (Tuple.first template.spacing)
2280+ ++ "-space-y-"
2281+ ++ lengthClassName (Tuple.second template.spacing)
2282+
2283+ ySpacing =
2284+ toGridLength (Tuple.second template.spacing)
2285+
2286+ xSpacing =
2287+ toGridLength (Tuple.first template.spacing)
2288+
2289+ toGridLength x =
2290+ toGridLengthHelper Nothing Nothing x
2291+
2292+ toGridLengthHelper minimum maximum x =
2293+ case x of
2294+ Px px ->
2295+ String.fromInt px ++ "px"
2296+
2297+ Content ->
2298+ case ( minimum, maximum ) of
2299+ ( Nothing, Nothing ) ->
2300+ "max-content"
2301+
2302+ ( Just minSize, Nothing ) ->
2303+ "minmax(" ++ String.fromInt minSize ++ "px, " ++ "max-content)"
2304+
2305+ ( Nothing, Just maxSize ) ->
2306+ "minmax(max-content, " ++ String.fromInt maxSize ++ "px)"
2307+
2308+ ( Just minSize, Just maxSize ) ->
2309+ "minmax(" ++ String.fromInt minSize ++ "px, " ++ String.fromInt maxSize ++ "px)"
2310+
2311+ Fill i ->
2312+ case ( minimum, maximum ) of
2313+ ( Nothing, Nothing ) ->
2314+ String.fromInt i ++ "fr"
2315+
2316+ ( Just minSize, Nothing ) ->
2317+ "minmax(" ++ String.fromInt minSize ++ "px, " ++ String.fromInt i ++ "fr" ++ "fr)"
2318+
2319+ ( Nothing, Just maxSize ) ->
2320+ "minmax(max-content, " ++ String.fromInt maxSize ++ "px)"
2321+
2322+ ( Just minSize, Just maxSize ) ->
2323+ "minmax(" ++ String.fromInt minSize ++ "px, " ++ String.fromInt maxSize ++ "px)"
2324+
2325+ Min m len ->
2326+ toGridLengthHelper (Just m) maximum len
2327+
2328+ Max m len ->
2329+ toGridLengthHelper minimum (Just m) len
2330+
2331+ msColumns =
2332+ template.columns
2333+ |> List.map toGridLength
2334+ |> String.join ySpacing
2335+ |> (\x -> "-ms-grid-columns: " ++ x ++ ";")
2336+
2337+ msRows =
2338+ template.columns
2339+ |> List.map toGridLength
2340+ |> String.join ySpacing
2341+ |> (\x -> "-ms-grid-rows: " ++ x ++ ";")
2342+
2343+ base =
2344+ class ++ "{" ++ msColumns ++ msRows ++ "}"
2345+
2346+ columns =
2347+ template.columns
2348+ |> List.map toGridLength
2349+ |> String.join " "
2350+ |> (\x -> "grid-template-columns: " ++ x ++ ";")
2351+
2352+ rows =
2353+ template.rows
2354+ |> List.map toGridLength
2355+ |> String.join " "
2356+ |> (\x -> "grid-template-rows: " ++ x ++ ";")
2357+
2358+ gapX =
2359+ "grid-column-gap:" ++ toGridLength (Tuple.first template.spacing) ++ ";"
2360+
2361+ gapY =
2362+ "grid-row-gap:" ++ toGridLength (Tuple.second template.spacing) ++ ";"
2363+
2364+ modernGrid =
2365+ class ++ "{" ++ columns ++ rows ++ gapX ++ gapY ++ "}"
2366+
2367+ supports =
2368+ "@supports (display:grid) {" ++ modernGrid ++ "}"
2369+ in
2370+ base ++ supports
2371+
2372+ GridPosition position ->
2373+ let
2374+ class =
2375+ ".grid-pos-"
2376+ ++ String.fromInt position.row
2377+ ++ "-"
2378+ ++ String.fromInt position.col
2379+ ++ "-"
2380+ ++ String.fromInt position.width
2381+ ++ "-"
2382+ ++ String.fromInt position.height
2383+
2384+ msPosition =
2385+ String.join " "
2386+ [ "-ms-grid-row: "
2387+ ++ String.fromInt position.row
2388+ ++ ";"
2389+ , "-ms-grid-row-span: "
2390+ ++ String.fromInt position.height
2391+ ++ ";"
2392+ , "-ms-grid-column: "
2393+ ++ String.fromInt position.col
2394+ ++ ";"
2395+ , "-ms-grid-column-span: "
2396+ ++ String.fromInt position.width
2397+ ++ ";"
2398+ ]
2399+
2400+ base =
2401+ class ++ "{" ++ msPosition ++ "}"
2402+
2403+ modernPosition =
2404+ String.join " "
2405+ [ "grid-row: "
2406+ ++ String.fromInt position.row
2407+ ++ " / "
2408+ ++ String.fromInt (position.row + position.height)
2409+ ++ ";"
2410+ , "grid-column: "
2411+ ++ String.fromInt position.col
2412+ ++ " / "
2413+ ++ String.fromInt (position.col + position.width)
2414+ ++ ";"
2415+ ]
2416+
2417+ modernGrid =
2418+ class ++ "{" ++ modernPosition ++ "}"
2419+
2420+ supports =
2421+ "@supports (display:grid) {" ++ modernGrid ++ "}"
2422+ in
2423+ base ++ supports
2424+
2425+ PseudoSelector class styles ->
2426+ let
2427+ renderPseudoRule style =
2428+ renderStyleRule style (Just class)
2429+ in
2430+ List.map renderPseudoRule styles
2431+ |> String.join " "
2432+
2433+ Transform transform ->
2434+ let
2435+ val =
2436+ transformValue transform
2437+
2438+ class =
2439+ transformClass transform
2440+ in
2441+ case ( class, val ) of
2442+ ( Just cls, Just v ) ->
2443+ renderStyle
2444+ maybePseudo
2445+ ("." ++ cls)
2446+ [ Property "transform"
2447+ v
2448+ ]
2449+
2450+ _ ->
2451+ ""
2452+
2453+ combine style rendered =
2454+ { rendered
2455+ | rules = rendered.rules ++ renderStyleRule style Nothing
2456+ , topLevel =
2457+ case renderTopLevels style of
2458+ Nothing ->
2459+ rendered.topLevel
2460+
2461+ Just topLevel ->
2462+ rendered.topLevel ++ topLevel
2463+ }
2464+ in
2465+ case List.foldl combine { rules = "", topLevel = "" } stylesheet of
2466+ { topLevel, rules } ->
2467+ topLevel ++ rules
2468+
2469+
2470+lengthClassName : Length -> String
2471+lengthClassName x =
2472+ case x of
2473+ Px px ->
2474+ String.fromInt px ++ "px"
2475+
2476+ Content ->
2477+ "auto"
2478+
2479+ Fill i ->
2480+ String.fromInt i ++ "fr"
2481+
2482+ Min min len ->
2483+ "min" ++ String.fromInt min ++ lengthClassName len
2484+
2485+ Max max len ->
2486+ "max" ++ String.fromInt max ++ lengthClassName len
2487+
2488+
2489+formatDropShadow shadow =
2490+ String.join " "
2491+ [ String.fromFloat (Tuple.first shadow.offset) ++ "px"
2492+ , String.fromFloat (Tuple.second shadow.offset) ++ "px"
2493+ , String.fromFloat shadow.blur ++ "px"
2494+ , formatColor shadow.color
2495+ ]
2496+
2497+
2498+formatTextShadow shadow =
2499+ String.join " "
2500+ [ String.fromFloat (Tuple.first shadow.offset) ++ "px"
2501+ , String.fromFloat (Tuple.second shadow.offset) ++ "px"
2502+ , String.fromFloat shadow.blur ++ "px"
2503+ , formatColor shadow.color
2504+ ]
2505+
2506+
2507+textShadowName shadow =
2508+ String.concat
2509+ [ "txt"
2510+ , String.fromFloat (Tuple.first shadow.offset) ++ "px"
2511+ , String.fromFloat (Tuple.second shadow.offset) ++ "px"
2512+ , String.fromFloat shadow.blur ++ "px"
2513+ , formatColorClass shadow.color
2514+ ]
2515+
2516+
2517+formatBoxShadow shadow =
2518+ String.join " " <|
2519+ List.filterMap identity
2520+ [ if shadow.inset then
2521+ Just "inset"
2522+ else
2523+ Nothing
2524+ , Just <| String.fromFloat (Tuple.first shadow.offset) ++ "px"
2525+ , Just <| String.fromFloat (Tuple.second shadow.offset) ++ "px"
2526+ , Just <| String.fromFloat shadow.blur ++ "px"
2527+ , Just <| String.fromFloat shadow.size ++ "px"
2528+ , Just <| formatColor shadow.color
2529+ ]
2530+
2531+
2532+boxShadowName shadow =
2533+ String.concat <|
2534+ [ if shadow.inset then
2535+ "box-inset"
2536+ else
2537+ "box-"
2538+ , String.fromFloat (Tuple.first shadow.offset) ++ "px"
2539+ , String.fromFloat (Tuple.second shadow.offset) ++ "px"
2540+ , String.fromFloat shadow.blur ++ "px"
2541+ , String.fromFloat shadow.size ++ "px"
2542+ , formatColorClass shadow.color
2543+ ]
2544+
2545+
2546+floatClass : Float -> String
2547+floatClass x =
2548+ String.fromInt (round (x * 255))
2549+
2550+
2551+formatColor : Color -> String
2552+formatColor (Rgba red green blue alpha) =
2553+ "rgba("
2554+ ++ String.fromInt (round (red * 255))
2555+ ++ ("," ++ String.fromInt (round (green * 255)))
2556+ ++ ("," ++ String.fromInt (round (blue * 255)))
2557+ ++ ("," ++ String.fromFloat alpha ++ ")")
2558+
2559+
2560+formatColorClass : Color -> String
2561+formatColorClass (Rgba red green blue alpha) =
2562+ floatClass red
2563+ ++ "-"
2564+ ++ floatClass green
2565+ ++ "-"
2566+ ++ floatClass blue
2567+ ++ "-"
2568+ ++ floatClass alpha
2569+
2570+
2571+spacingName x y =
2572+ "spacing-" ++ String.fromInt x ++ "-" ++ String.fromInt y
2573+
2574+
2575+paddingName top right bottom left =
2576+ "pad-"
2577+ ++ String.fromInt top
2578+ ++ "-"
2579+ ++ String.fromInt right
2580+ ++ "-"
2581+ ++ String.fromInt bottom
2582+ ++ "-"
2583+ ++ String.fromInt left
2584+
2585+
2586+getStyleName : Style -> String
2587+getStyleName style =
2588+ case style of
2589+ Shadows name _ ->
2590+ name
2591+
2592+ Transparency name o ->
2593+ name
2594+
2595+ Style class _ ->
2596+ class
2597+
2598+ FontFamily name _ ->
2599+ name
2600+
2601+ FontSize i ->
2602+ "font-size-" ++ String.fromInt i
2603+
2604+ Single class _ _ ->
2605+ class
2606+
2607+ Colored class _ _ ->
2608+ class
2609+
2610+ SpacingStyle cls x y ->
2611+ cls
2612+
2613+ PaddingStyle cls top right bottom left ->
2614+ cls
2615+
2616+ GridTemplateStyle template ->
2617+ "grid-rows-"
2618+ ++ String.join "-" (List.map lengthClassName template.rows)
2619+ ++ "-cols-"
2620+ ++ String.join "-" (List.map lengthClassName template.columns)
2621+ ++ "-space-x-"
2622+ ++ lengthClassName (Tuple.first template.spacing)
2623+ ++ "-space-y-"
2624+ ++ lengthClassName (Tuple.second template.spacing)
2625+
2626+ GridPosition pos ->
2627+ "gp grid-pos-"
2628+ ++ String.fromInt pos.row
2629+ ++ "-"
2630+ ++ String.fromInt pos.col
2631+ ++ "-"
2632+ ++ String.fromInt pos.width
2633+ ++ "-"
2634+ ++ String.fromInt pos.height
2635+
2636+ PseudoSelector selector subStyle ->
2637+ let
2638+ name =
2639+ case selector of
2640+ Focus ->
2641+ "fs"
2642+
2643+ Hover ->
2644+ "hv"
2645+
2646+ Active ->
2647+ "act"
2648+ in
2649+ List.map
2650+ (\sty ->
2651+ case getStyleName sty of
2652+ "" ->
2653+ ""
2654+
2655+ styleName ->
2656+ styleName ++ "-" ++ name
2657+ )
2658+ subStyle
2659+ |> String.join " "
2660+
2661+ Transform x ->
2662+ Maybe.withDefault "" (transformClass x)
2663+
2664+
2665+
2666+{- Constants -}
2667+
2668+
2669+asGrid : LayoutContext
2670+asGrid =
2671+ AsGrid
2672+
2673+
2674+asRow : LayoutContext
2675+asRow =
2676+ AsRow
2677+
2678+
2679+asColumn : LayoutContext
2680+asColumn =
2681+ AsColumn
2682+
2683+
2684+asEl : LayoutContext
2685+asEl =
2686+ AsEl
2687+
2688+
2689+asParagraph : LayoutContext
2690+asParagraph =
2691+ AsParagraph
2692+
2693+
2694+asTextColumn : LayoutContext
2695+asTextColumn =
2696+ AsTextColumn
2697+
2698+
2699+
2700+{- Mapping -}
2701+
2702+
2703+map : (msg -> msg1) -> Element msg -> Element msg1
2704+map fn el =
2705+ case el of
2706+ Styled styled ->
2707+ Styled
2708+ { styles = styled.styles
2709+ , html = \add context -> VirtualDom.map fn <| styled.html add context
2710+ }
2711+
2712+ Unstyled html ->
2713+ Unstyled (VirtualDom.map fn << html)
2714+
2715+ Text str ->
2716+ Text str
2717+
2718+ Empty ->
2719+ Empty
2720+
2721+
2722+mapAttr : (msg -> msg1) -> Attribute aligned msg -> Attribute aligned msg1
2723+mapAttr fn attr =
2724+ case attr of
2725+ NoAttribute ->
2726+ NoAttribute
2727+
2728+ Describe description ->
2729+ Describe description
2730+
2731+ AlignX x ->
2732+ AlignX x
2733+
2734+ AlignY y ->
2735+ AlignY y
2736+
2737+ Width x ->
2738+ Width x
2739+
2740+ Height x ->
2741+ Height x
2742+
2743+ Class x y ->
2744+ Class x y
2745+
2746+ StyleClass flag style ->
2747+ StyleClass flag style
2748+
2749+ Nearby location elem ->
2750+ Nearby location (map fn elem)
2751+
2752+ Attr htmlAttr ->
2753+ Attr (VirtualDom.mapAttribute fn htmlAttr)
2754+
2755+ TransformComponent fl trans ->
2756+ TransformComponent fl trans
2757+
2758+
2759+mapAttrFromStyle : (msg -> msg1) -> Attribute Never msg -> Attribute () msg1
2760+mapAttrFromStyle fn attr =
2761+ case attr of
2762+ NoAttribute ->
2763+ NoAttribute
2764+
2765+ Describe description ->
2766+ Describe description
2767+
2768+ AlignX x ->
2769+ AlignX x
2770+
2771+ AlignY y ->
2772+ AlignY y
2773+
2774+ Width x ->
2775+ Width x
2776+
2777+ Height x ->
2778+ Height x
2779+
2780+ -- invalidation key "border-color" as opposed to "border-color-10-10-10" that will be the key for the class
2781+ Class x y ->
2782+ Class x y
2783+
2784+ StyleClass flag style ->
2785+ StyleClass flag style
2786+
2787+ Nearby location elem ->
2788+ Nearby location (map fn elem)
2789+
2790+ Attr htmlAttr ->
2791+ Attr (VirtualDom.mapAttribute fn htmlAttr)
2792+
2793+ TransformComponent fl trans ->
2794+ TransformComponent fl trans
2795+
2796+
2797+unwrapDecorations : List (Attribute Never Never) -> List Style
2798+unwrapDecorations attrs =
2799+ case List.foldl unwrapDecsHelper ( [], Untransformed ) attrs of
2800+ ( styles, transform ) ->
2801+ Transform transform :: styles
2802+
2803+
2804+unwrapDecsHelper attr ( styles, trans ) =
2805+ case removeNever attr of
2806+ StyleClass _ style ->
2807+ ( style :: styles, trans )
2808+
2809+ TransformComponent flag component ->
2810+ ( styles, composeTransformation trans component )
2811+
2812+ _ ->
2813+ ( styles, trans )
2814+
2815+
2816+removeNever : Attribute Never Never -> Attribute () msg
2817+removeNever style =
2818+ mapAttrFromStyle Basics.never style
2819+
2820+
2821+tag : String -> Style -> Style
2822+tag label style =
2823+ case style of
2824+ Single class prop val ->
2825+ Single (label ++ "-" ++ class) prop val
2826+
2827+ Colored class prop val ->
2828+ Colored (label ++ "-" ++ class) prop val
2829+
2830+ Style class props ->
2831+ Style (label ++ "-" ++ class) props
2832+
2833+ Transparency class o ->
2834+ Transparency (label ++ "-" ++ class) o
2835+
2836+ x ->
2837+ x
2838+
2839+
2840+onlyStyles : Attribute aligned msg -> Maybe Style
2841+onlyStyles attr =
2842+ case attr of
2843+ StyleClass _ style ->
2844+ Just style
2845+
2846+ _ ->
2847+ Nothing