(.require [library [lux (.except and) [control ["[0]" maybe]] [data ["[0]" text (.only) ["%" \\format (.only format)] ["[0]" encoding (.only Encoding)]] [collection ["[0]" list (.use "[1]#[0]" functor)]]] [math [number ["[0]" nat]]] [meta [type ["[0]" primitive (.except Frame def)]]] [world [net (.only URL)]]]] ["[0]" / ["[1][0]" selector (.only Selector Combinator Specializer Generic)] ["[1][0]" value (.only Value Animation Percentage)] ["[1][0]" property (.only Property)] ["[1][0]" font (.only Font)] ["[1][0]" style] ["[1][0]" query (.only Query)]]) (primitive.def .public Common Any) (primitive.def .public Special Any) (primitive.def .public (CSS brand) Text (def .public css (-> (CSS Any) Text) (|>> representation)) (def .public empty (CSS Any) (abstraction "")) (type .public Style (List (Ex (_ brand) [(Property brand) (Value brand)]))) (def .public (rule selector style) (-> (Selector Any) Style (CSS Common)) (abstraction (format (/selector.selector selector) "{" (/style.inline (/style.style style)) "}"))) (def .public char_set (-> Encoding (CSS Special)) (|>> encoding.name %.text (text.enclosed ["@charset " ";"]) abstraction)) (def .public (font font) (-> Font (CSS Special)) (let [with_unicode (when (the /font.#unicode_range font) {.#Some unicode_range} (let [unicode_range' (format "U+" (at nat.hex encoded (the /font.#start unicode_range)) "-" (at nat.hex encoded (the /font.#end unicode_range)))] (list ["unicode-range" unicode_range'])) {.#None} (list))] (|> (list.partial ["font-family" (the /font.#family font)] ["src" (format "url(" (the /font.#source font) ")")] ["font-stretch" (|> font (the /font.#stretch) (maybe.else /value.normal_stretch) /value.value)] ["font-style" (|> font (the /font.#style) (maybe.else /value.normal_style) /value.value)] ["font-weight" (|> font (the /font.#weight) (maybe.else /value.normal_weight) /value.value)] with_unicode) (list#each (function (_ [property value]) (format property ": " value ";"))) text.together (text.enclosed ["{" "}"]) (format "@font-face") abstraction))) (def .public (import url query) (-> URL (Maybe Query) (CSS Special)) (abstraction (format (format "@import url(" (%.text url) ")") (when query {.#Some query} (format " " (/query.query query)) {.#None} "") ";"))) (def separator text.new_line) (type .public Frame (Record [#when (Value Percentage) #what Style])) (def .public (key_frames animation frames) (-> (Value Animation) (List Frame) (CSS Special)) (abstraction (format "@keyframes " (/value.value animation) " {" (|> frames (list#each (function (_ frame) (format (/value.value (the #when frame)) " {" (/style.inline (/style.style (the #what frame))) "}"))) (text.interposed ..separator)) "}"))) (def !composite (template (!composite
 )
      [(abstraction
        (format (representation 
)
                ..separator
                (representation )))]))
  
  (def .public (and pre post)
    (All (_ kind) (-> (CSS kind) (CSS kind) (CSS kind)))
    (!composite pre post))

  (def .public (in_context combinator selector css)
    (-> Combinator (Selector Any) (CSS Common) (CSS Common))
    (|> css
        representation
        (text.all_split_by ..separator)
        (list#each (let [prefix (|> selector
                                    (combinator (/selector.tag ""))
                                    /selector.selector)]
                     (|>> (format prefix))))
        (text.interposed ..separator)
        abstraction))

  (def .public (dependent combinator selector style inner)
    (-> Combinator (Selector Any) Style (CSS Common) (CSS Common))
    (!composite (..rule selector style)
                (..in_context combinator selector inner)))

  (with_template [ ]
    [(def .public 
       (-> (Selector Any) Style (CSS Common) (CSS Common))
       (..dependent ))]

    [with_descendants /selector.in]
    [with_children /selector.sub]
    )

  (def .public (in_case specializer selector css)
    (All (_ kind)
      (-> (Specializer kind) (Selector (Generic Any)) (CSS Common) (CSS Common)))
    (|> css
        representation
        (text.all_split_by ..separator)
        (list#each (let [prefix (|> selector
                                    (specializer (as_expected (/selector.tag "")))
                                    /selector.selector)]
                     (|>> (format prefix))))
        (text.interposed ..separator)
        abstraction))

  (def .public (specialized combinator selector style inner)
    (All (_ kind)
      (-> (Specializer kind) (Selector (Generic Any)) Style (CSS Common) (CSS Common)))
    (!composite (..rule selector style)
                (..in_case combinator selector inner)))

  (with_template [ ]
    [(def .public 
       (-> (Selector (Generic Any)) Style (CSS Common) (CSS Common))
       (..specialized ))]

    [with_case /selector.and]
    [with_part /selector.at]
    [with_element /selector.for]
    )
  )