@@ -80,12 +80,12 @@ module Internal.Model exposing
8080 , pageClass
8181 , paragraphClass
8282 , reduceRecursive
83− , reduceRecursiveCalcName
8483 , reduceStyles
8584 , reduceStylesRecursive
8685 , removeNever
87− , renderFocusStyle
88− , renderFont
86+ , renderFocusStyle
87+ -- , renderFont
88+
8989 , renderFontClassName
9090 , renderHeight
9191 , renderRoot
@@ -93,24 +93,15 @@ module Internal.Model exposing
9393 , rootStyle
9494 , rowClass
9595 , singleClass
96− , skippable
97− , sortedReduce
9896 , spacingName
9997 , staticRoot
10098 , tag
101− , textElement
102− , textElementFill
10399 , textShadowName
104100 , toHtml
105101 , toStyleSheet
106− , toStyleSheetString
107102 , transformClass
108− , transformValue
109− , unit
110103 , unstyled
111− , untransformed
112104 , unwrapDecorations
113− , unwrapDecsHelper
114105 )
115106
116107{-| -}
@@ -213,12 +204,26 @@ type PseudoClass
213204 | Active
214205
215206
207+{-| -}
208+type alias Adjustment =
209+ { capital : Float
210+ , lowercase : Float
211+ , baseline : Float
212+ , descender : Float
213+ }
214+
215+
216216type Font
217217 = Serif
218218 | SansSerif
219219 | Monospace
220220 | Typeface String
221221 | ImportFont String String
222+ | FontWith
223+ { name : String
224+ , url : Maybe String
225+ , adjustment : Adjustment
226+ }
222227
223228
224229type Property
@@ -1490,34 +1495,32 @@ createElement context children rendered =
14901495 -- Maybe we could unpack text elements in a paragraph as well,
14911496 -- however, embedded elements that are larger than the line height will overlap with exisitng text.
14921497 -- I don't think that's what we want.
1493− if
1494− context
1495− == asEl
1496− || context
1497− == asParagraph
1498− then
1499− ( VirtualDom.text
1500− (if context == asParagraph then
1501− str
1502−
1503− else
1504− str
1505− )
1506− :: htmls
1507− , existingStyles
1508− )
1509−
1510− else
1511− ( textElement
1512− (if context == asParagraph then
1513− str
1514−
1515− else
1516− str
1517− )
1518− :: htmls
1519− , existingStyles
1498+ -- if
1499+ -- context
1500+ -- == asEl
1501+ -- || context
1502+ -- == asParagraph
1503+ -- then
1504+ -- ( VirtualDom.text
1505+ -- (if context == asParagraph then
1506+ -- str
1507+ -- else
1508+ -- str
1509+ -- )
1510+ -- :: htmls
1511+ -- , existingStyles
1512+ -- )
1513+ -- else
1514+ ( textElement
1515+ (if context == asParagraph then
1516+ str
1517+
1518+ else
1519+ str
15201520 )
1521+ :: htmls
1522+ , existingStyles
1523+ )
15211524
15221525 Empty ->
15231526 ( htmls, existingStyles )
@@ -1559,28 +1562,27 @@ createElement context children rendered =
15591562 -- TEXT OPTIMIZATION
15601563 -- You can have raw text if the element is an el, and has `width-content` and `height-content`
15611564 -- Same if it's a column or row with one child and width-content, height-content
1562− if
1563− context
1564− == asEl
1565− || context
1566− == asParagraph
1567− then
1568− ( ( key
1569− , VirtualDom.text
1570− str
1571− )
1572− :: htmls
1573− , existingStyles
1574− )
1575−
1576− else
1577− ( ( key
1578− , textElement
1579− str
1580− )
1581− :: htmls
1582− , existingStyles
1583− )
1565+ -- if
1566+ -- context
1567+ -- == asEl
1568+ -- || context
1569+ -- == asParagraph
1570+ -- then
1571+ -- ( ( key
1572+ -- , VirtualDom.text
1573+ -- str
1574+ -- )
1575+ -- :: htmls
1576+ -- , existingStyles
1577+ -- )
1578+ -- else
1579+ ( ( key
1580+ , textElement
1581+ str
1582+ )
1583+ :: htmls
1584+ , existingStyles
1585+ )
15841586
15851587 Empty ->
15861588 ( htmls, existingStyles )
@@ -2051,6 +2053,12 @@ renderFontClassName font current =
20512053 |> String.toLower
20522054 |> String.words
20532055 |> String.join "-"
2056+
2057+ FontWith { name } ->
2058+ name
2059+ |> String.toLower
2060+ |> String.words
2061+ |> String.join "-"
20542062 )
20552063
20562064
@@ -2160,66 +2168,279 @@ optionsToRecord options =
21602168 options
21612169
21622170
2163−renderFont : List Font -> String
2164−renderFont families =
2171+toStyleSheet : OptionRecord -> List Style -> VirtualDom.Node msg
2172+toStyleSheet options styleSheet =
2173+ VirtualDom.node "style" [] [ VirtualDom.text (toStyleSheetString options styleSheet) ]
2174+
2175+
2176+
2177+-- case typefaceAdjustment typefaces of
2178+-- Nothing ->
2179+-- ""
2180+-- Just ( parentAdj, textAdjustment ) ->
2181+-- String.join " "
2182+-- [ renderStyle
2183+-- maybePseudo
2184+-- ("."
2185+-- ++ name
2186+-- ++ "."
2187+-- ++ classes.sizeByCapital
2188+-- ++ ", "
2189+-- ++ "."
2190+-- ++ name
2191+-- ++ " ."
2192+-- ++ classes.sizeByCapital
2193+-- )
2194+-- parentAdj
2195+-- , renderStyle
2196+-- maybePseudo
2197+-- ("."
2198+-- ++ name
2199+-- ++ "."
2200+-- ++ classes.sizeByCapital
2201+-- ++ "> ."
2202+-- ++ Internal.Style.classes.text
2203+-- ++ ", ."
2204+-- ++ name
2205+-- ++ " ."
2206+-- ++ classes.sizeByCapital
2207+-- ++ " > ."
2208+-- ++ Internal.Style.classes.text
2209+-- )
2210+-- textAdjustment
2211+-- ]
2212+-- renderTopLevels rule =
2213+-- case rule of
2214+-- FontFamily name typefaces ->
2215+-- let
2216+-- getImports font =
2217+-- case font of
2218+-- ImportFont _ url ->
2219+-- Just ("@import url('" ++ url ++ "');")
2220+-- FontWith { url } ->
2221+-- case url of
2222+-- Just x ->
2223+-- Just ("@import url('" ++ x ++ "');")
2224+-- Nothing ->
2225+-- Nothing
2226+-- _ ->
2227+-- Nothing
2228+-- in
2229+-- typefaces
2230+-- |> List.filterMap getImports
2231+-- |> String.join "\n"
2232+-- |> Just
2233+-- _ ->
2234+-- Nothing
2235+
2236+
2237+renderTopLevelValues rules =
21652238 let
2166− fontName font =
2239+ withImport font =
21672240 case font of
2168− Serif ->
2169− "serif"
2241+ ImportFont _ url ->
2242+ Just ("@import url('" ++ url ++ "');")
21702243
2171− SansSerif ->
2172− "sans-serif"
2244+ FontWith with ->
2245+ case with.url of
2246+ Just x ->
2247+ Just ("@import url('" ++ x ++ "');")
21732248
2174− Monospace ->
2175− "monospace"
2249+ Nothing ->
2250+ Nothing
21762251
2177− Typeface name ->
2178− "\"" ++ name ++ "\""
2252+ _ ->
2253+ Nothing
21792254
2180− ImportFont name url ->
2181− "\"" ++ name ++ "\""
2182− in
2183− families
2184− |> List.map fontName
2185− |> String.join ", "
2255+ allNames =
2256+ List.map Tuple.first rules
21862257
2258+ fontImports ( name, typefaces ) =
2259+ let
2260+ imports =
2261+ String.join "\n" (List.filterMap withImport typefaces)
2262+ in
2263+ imports
21872264
2188−toStyleSheet : OptionRecord -> List Style -> VirtualDom.Node msg
2189−toStyleSheet options styleSheet =
2190− VirtualDom.node "style" [] [ VirtualDom.text (toStyleSheetString options styleSheet) ]
2265+ fontAdjustments ( name, typefaces ) =
2266+ case typefaceAdjustment typefaces of
2267+ Nothing ->
2268+ String.join ""
2269+ (List.map (renderNullAdjustmentRule name) allNames)
21912270
2271+ Just adjustment ->
2272+ String.join ""
2273+ (List.map (renderFontAdjustmentRule name adjustment) allNames)
2274+ in
2275+ String.join "\n" (List.map fontImports rules)
2276+ ++ String.join "\n" (List.map fontAdjustments rules)
21922277
2193−toStyleSheetString : OptionRecord -> List Style -> String
2194−toStyleSheetString options stylesheet =
2278+
2279+renderNullAdjustmentRule fontToAdjust otherFontName =
21952280 let
2196− renderTopLevels rule =
2197− case rule of
2198− FontFamily name typefaces ->
2199− let
2200− getImports font =
2201− case font of
2202− ImportFont _ url ->
2203− Just ("@import url('" ++ url ++ "');")
2281+ name =
2282+ if fontToAdjust == otherFontName then
2283+ fontToAdjust
22042284
2205− _ ->
2206− Nothing
2207− in
2208− typefaces
2209− |> List.filterMap getImports
2210− |> String.join "\n"
2211− |> Just
2285+ else
2286+ otherFontName ++ " ." ++ fontToAdjust
2287+ in
2288+ String.join " "
2289+ [ bracket
2290+ ("."
2291+ ++ name
2292+ ++ "."
2293+ ++ classes.sizeByCapital
2294+ ++ ", "
2295+ ++ "."
2296+ ++ name
2297+ ++ " ."
2298+ ++ classes.sizeByCapital
2299+ )
2300+ [ ( "line-height", "1" )
2301+ ]
2302+ , bracket
2303+ ("."
2304+ ++ name
2305+ ++ "."
2306+ ++ classes.sizeByCapital
2307+ ++ "> ."
2308+ ++ Internal.Style.classes.text
2309+ ++ ", ."
2310+ ++ name
2311+ ++ " ."
2312+ ++ classes.sizeByCapital
2313+ ++ " > ."
2314+ ++ Internal.Style.classes.text
2315+ )
2316+ [ ( "vertical-align", "0" )
2317+ , ( "line-height", "1" )
2318+ ]
2319+ ]
22122320
2213− _ ->
2214− Nothing
22152321
2216− renderProps force (Property key val) existing =
2217− if force then
2218− existing ++ "\n " ++ key ++ ": " ++ val ++ " !important;"
2322+renderFontAdjustmentRule fontToAdjust ( parentAdj, textAdjustment ) otherFontName =
2323+ let
2324+ name =
2325+ if fontToAdjust == otherFontName then
2326+ fontToAdjust
22192327
22202328 else
2221− existing ++ "\n " ++ key ++ ": " ++ val ++ ";"
2329+ otherFontName ++ " ." ++ fontToAdjust
2330+ in
2331+ String.join " "
2332+ [ bracket
2333+ ("."
2334+ ++ name
2335+ ++ "."
2336+ ++ classes.sizeByCapital
2337+ ++ ", "
2338+ ++ "."
2339+ ++ name
2340+ ++ " ."
2341+ ++ classes.sizeByCapital
2342+ )
2343+ parentAdj
2344+ , bracket
2345+ ("."
2346+ ++ name
2347+ ++ "."
2348+ ++ classes.sizeByCapital
2349+ ++ "> ."
2350+ ++ Internal.Style.classes.text
2351+ ++ ", ."
2352+ ++ name
2353+ ++ " ."
2354+ ++ classes.sizeByCapital
2355+ ++ " > ."
2356+ ++ Internal.Style.classes.text
2357+ )
2358+ textAdjustment
2359+ ]
2360+
2361+
2362+bracket selector rules =
2363+ let
2364+ renderPair ( name, val ) =
2365+ name ++ ": " ++ val ++ ";"
2366+ in
2367+ selector ++ " {" ++ String.join "" (List.map renderPair rules) ++ "}"
2368+
2369+
2370+fontAdjustmentRules converted =
2371+ ( [ ( "display", "block" )
2372+ , ( "line-height", String.fromFloat converted.height )
2373+ ]
2374+ , [ ( "display", "inline-block" )
2375+ , ( "line-height", String.fromFloat converted.height )
2376+ , ( "vertical-align", String.fromFloat converted.vertical ++ "em" )
2377+ ]
2378+ )
2379+
2380+
2381+typefaceAdjustment typefaces =
2382+ List.foldl
2383+ (\face found ->
2384+ case found of
2385+ Nothing ->
2386+ case face of
2387+ FontWith with ->
2388+ Just
2389+ (fontAdjustmentRules
2390+ (.capital (convertAdjustment with.adjustment))
2391+ )
2392+
2393+ _ ->
2394+ found
22222395
2396+ Just _ ->
2397+ found
2398+ )
2399+ Nothing
2400+ typefaces
2401+
2402+
2403+fontName font =
2404+ case font of
2405+ Serif ->
2406+ "serif"
2407+
2408+ SansSerif ->
2409+ "sans-serif"
2410+
2411+ Monospace ->
2412+ "monospace"
2413+
2414+ Typeface name ->
2415+ "\"" ++ name ++ "\""
2416+
2417+ ImportFont name url ->
2418+ "\"" ++ name ++ "\""
2419+
2420+ FontWith { name } ->
2421+ "\"" ++ name ++ "\""
2422+
2423+
2424+topLevelValue rule =
2425+ case rule of
2426+ FontFamily name typefaces ->
2427+ Just ( name, typefaces )
2428+
2429+ _ ->
2430+ Nothing
2431+
2432+
2433+renderProps force (Property key val) existing =
2434+ if force then
2435+ existing ++ "\n " ++ key ++ ": " ++ val ++ " !important;"
2436+
2437+ else
2438+ existing ++ "\n " ++ key ++ ": " ++ val ++ ";"
2439+
2440+
2441+toStyleSheetString : OptionRecord -> List Style -> String
2442+toStyleSheetString options stylesheet =
2443+ let
22232444 renderStyle maybePseudo selector props =
22242445 case maybePseudo of
22252446 Nothing ->
@@ -2308,10 +2529,19 @@ toStyleSheetString options stylesheet =
23082529 ]
23092530
23102531 FontFamily name typefaces ->
2311− renderStyle
2312− maybePseudo
2313− ("." ++ name)
2314− [ Property "font-family" (renderFont typefaces)
2532+ let
2533+ families =
2534+ Property "font-family"
2535+ (typefaces
2536+ |> List.map fontName
2537+ |> String.join ", "
2538+ )
2539+ in
2540+ String.join " "
2541+ [ renderStyle
2542+ maybePseudo
2543+ ("." ++ name)
2544+ [ families ]
23152545 ]
23162546
23172547 Single class prop val ->
@@ -2659,20 +2889,19 @@ toStyleSheetString options stylesheet =
26592889 ""
26602890
26612891 combine style rendered =
2662− { rendered
2663− | rules = rendered.rules ++ renderStyleRule style Nothing
2664− , topLevel =
2665− case renderTopLevels style of
2666− Nothing ->
2667− rendered.topLevel
2892+ { rules = rendered.rules ++ renderStyleRule style Nothing
2893+ , topLevel =
2894+ case topLevelValue style of
2895+ Nothing ->
2896+ rendered.topLevel
26682897
2669− Just topLevel ->
2670− rendered.topLevel ++ topLevel
2898+ Just topLevel ->
2899+ topLevel :: rendered.topLevel
26712900 }
26722901 in
2673− case List.foldl combine { rules = "", topLevel = "" } stylesheet of
2902+ case List.foldl combine { topLevel = [], rules = "" } stylesheet of
26742903 { topLevel, rules } ->
2675− topLevel ++ rules
2904+ renderTopLevelValues topLevel ++ rules
26762905
26772906
26782907lengthClassName : Length -> String
@@ -3058,3 +3287,66 @@ onlyStyles attr =
30583287
30593288 _ ->
30603289 Nothing
3290+
3291+
3292+
3293+{- Font Adjustments -}
3294+
3295+
3296+convertAdjustment adjustment =
3297+ let
3298+ lineHeight =
3299+ 1.5
3300+
3301+ base =
3302+ lineHeight
3303+
3304+ normalDescender =
3305+ (lineHeight - 1)
3306+ / 2
3307+
3308+ oldMiddle =
3309+ lineHeight / 2
3310+
3311+ newCapitalMiddle =
3312+ ((ascender - newBaseline) / 2) + newBaseline
3313+
3314+ newFullMiddle =
3315+ ((ascender - descender) / 2) + descender
3316+
3317+ lines =
3318+ [ adjustment.capital
3319+ , adjustment.baseline
3320+ , adjustment.descender
3321+ , adjustment.lowercase
3322+ ]
3323+
3324+ ascender =
3325+ Maybe.withDefault adjustment.capital (List.maximum lines)
3326+
3327+ descender =
3328+ Maybe.withDefault adjustment.descender (List.minimum lines)
3329+
3330+ newBaseline =
3331+ lines
3332+ |> List.filter (\x -> x /= descender)
3333+ |> List.minimum
3334+ |> Maybe.withDefault adjustment.baseline
3335+
3336+ capitalVertical =
3337+ (oldMiddle - newCapitalMiddle) * 2
3338+
3339+ fullVertical =
3340+ (oldMiddle - newFullMiddle) * 2
3341+ in
3342+ { full =
3343+ { vertical = fullVertical
3344+ , height =
3345+ (ascender - descender)
3346+ - abs fullVertical
3347+ }
3348+ , capital =
3349+ { vertical = capitalVertical
3350+ , height = (ascender - newBaseline) - abs capitalVertical
3351+ }
3352+ }